You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Windows: anywhere you want, but in regedit, set the HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.hammerill.mpv_host key "(Default)" value to its path.
And fill it with this:
{
"name": "com.hammerill.mpv_host",
"description": "Host for sending URLs to MPV",
"path": "/home/YOUR_USERNAME/Scripts/open_in_mpv.py",
"type": "stdio",
"allowed_origins": [
"chrome-extension://YOUR_EXTENSION_ID/"
]
}
Replacing YOUR_USERNAME and YOUR_EXTENSION_ID with actual values.
Restart Chrome and see if it works. You probably can open it in terminal to see eventual errors.
Credits
This script was built with help of Google Gemini 2.5 Pro. I leave the whole conversation of me and this LLM here for serenity:
I want to add a "Open in mpv" option to my right click menu in google chrome
Assistant
Of course! Adding an "Open in mpv" option to Chrome's right-click menu is a fantastic way to streamline your workflow.
Because of browser security restrictions, a web page (and its extensions) cannot directly execute a program on your computer. To bridge this gap, you need a two-part solution:
A Chrome Extension: This adds the option to your right-click menu.
A Native Messaging Host: A small helper program on your computer that the extension communicates with. The extension sends the URL to this host, and the host is what actually launches mpv.
Here are two methods to get this set up, from easiest to most advanced.
Method 1: The Easy Way (Recommended)
The simplest approach is to use a pre-built extension and host that someone has already created. The most popular and well-maintained one is "Play with mpv".
Step 1: Install the Chrome Extension
Go to the Chrome Web Store and install the "Play with mpv" extension.
Click on the green < > Code button and select Download ZIP.
Extract the downloaded ZIP file to a permanent location on your computer (e.g., inside your Documents or a "Scripts" folder).
Run the installation script for your operating system:
On Windows:
Navigate into the extracted folder.
Right-click on install-host.bat and select "Run as administrator".
A command prompt will appear and register the native host.
On macOS / Linux:
Open your Terminal.
Navigate to the extracted folder using the cd command. For example: cd ~/Downloads/play-with-mpv-handler-main
Make the script executable: chmod +x install-host.sh
Run the installer: ./install-host.sh
You might be prompted for your password if it needs to install to a system-wide directory.
Step 3: Ensure mpv is in your System's PATH
For the helper to find mpv, the mpv executable must be in your system's PATH.
Windows: When installing mpv (e.g., via Scoop, Chocolatey, or from a pre-compiled build), there is often an option to add it to the PATH. If not, you'll need to add the folder containing mpv.exe to your Environment Variables manually.
macOS: If you installed mpv using Homebrew (brew install mpv), it's already in your PATH.
Linux: If you installed mpv using your distribution's package manager (sudo apt install mpv, sudo dnf install mpv, etc.), it's already in your PATH.
Step 4: Use It!
You're all set! Now you can:
Right-click on any link that points to a video or audio file.
Right-click on a YouTube, Twitch, or other supported video page.
Select "Play with mpv".
mpv should launch and start playing the content.
Method 2: The DIY / Advanced Way
If you prefer not to use a third-party extension or want to understand how it works, you can build a minimal version yourself. This is more involved.
Part A: Create the Native Host Script
This script will receive the URL from Chrome and launch mpv. We'll use Python as it's simple and cross-platform.
Create a file named open_in_mpv.py and paste the following code into it:
#!/usr/bin/env python3importsysimportjsonimportstructimportsubprocess# On Windows, we need to set the process creation flags to hide the console window# that would otherwise pop up when we run mpv.# See: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flagsCREATE_NO_WINDOW=0x08000000defget_message():
"""Read a message from stdin and decode it."""raw_length=sys.stdin.buffer.read(4)
ifnotraw_length:
sys.exit(0)
message_length=struct.unpack('=I', raw_length)[0]
message=sys.stdin.buffer.read(message_length).decode('utf-8')
returnjson.loads(message)
try:
# Get the URL sent by the extensionurl=get_message()
# The command to execute. Add any custom mpv flags here.# For example: ['mpv', '--ytdl-format=best', url]command= ['mpv', url]
# Launch mpv in a new process, detached from our script.# Use CREATE_NO_WINDOW flag on Windows to prevent a cmd.exe flash.ifsys.platform=="win32":
subprocess.Popen(command, creationflags=CREATE_NO_WINDOW)
else:
subprocess.Popen(command)
exceptExceptionase:
# For debugging: if something goes wrong, write it to a file.# You can comment this out in production.withopen('/tmp/mpv_chrome_host.log', 'a') asf:
f.write(f"Error: {e}\n")
Save this script in a permanent location (e.g., C:\Users\YourUser\Scripts\ or ~/bin/).
Part B: Create the Host Manifest JSON
Chrome needs a manifest file to know where your script is and which extension is allowed to talk to it.
Create a file named com.my.mpv_host.json and paste the following into it:
{
"name": "com.my.mpv_host",
"description": "Host for sending URLs to MPV",
"path": "C:\\Path\\To\\Your\\open_in_mpv.py",
"type": "stdio",
"allowed_origins": [
"chrome-extension://PASTE_YOUR_EXTENSION_ID_HERE/"
]
}
Crucially, you must edit two things:
path: Replace "C:\\Path\\To\\Your\\open_in_mpv.py" with the full, absolute path to your Python script.
Windows: Use double backslashes (\\). Example: "C:\\Users\\Me\\Scripts\\open_in_mpv.py"
macOS/Linux: Use forward slashes (/). Example: "/home/me/bin/open_in_mpv.py"
allowed_origins: We will fill this in after creating the extension. Leave it as a placeholder for now.
Part C: Create the Chrome Extension
Create a new folder for your extension (e.g., my-mpv-extension).
Inside that folder, create a file named manifest.json:
{
"name": "DIY Open in mpv",
"version": "1.0",
"manifest_version": 3,
"description": "Right-click to open links in mpv player.",
"permissions": [
"contextMenus",
"nativeMessaging"
],
"background": {
"service_worker": "background.js"
}
}
In the same folder, create a file named background.js:
// The name of our native host, from its manifest file.constNATIVE_HOST_NAME="com.my.mpv_host";// Create the context menu item.chrome.runtime.onInstalled.addListener(()=>{chrome.contextMenus.create({id: "open-in-mpv",title: "Open Link in mpv",contexts: ["link","video","audio","page"]// Show on links, media, and pages});});// Handle the click event.chrome.contextMenus.onClicked.addListener((info,tab)=>{if(info.menuItemId==="open-in-mpv"){// The URL is in info.linkUrl if a link was clicked,// or info.pageUrl if the page background was clicked.consturl=info.linkUrl||info.pageUrl;if(url){// Connect to the native host and send the URL.constport=chrome.runtime.connectNative(NATIVE_HOST_NAME);port.postMessage(url);}}});
Part D: Put It All Together
Install the Extension:
Open Chrome and go to chrome://extensions.
Enable "Developer mode" in the top-right corner.
Click "Load unpacked" and select the folder you created for your extension (my-mpv-extension).
Your extension will appear. Copy its ID (a long string of random letters).
Update the Host Manifest:
Go back to your com.my.mpv_host.json file.
Replace "PASTE_YOUR_EXTENSION_ID_HERE" with the ID you just copied. The line should now look like this: "chrome-extension://abcdefghijklmnopqrstuvwxyz123456/".
Register the Native Host:
This is the final step, and it's platform-specific. You need to tell Chrome where your host manifest is.
Windows: Create a registry key. Open regedit and navigate to HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\.
Create a new key named com.my.mpv_host.
Set its (Default) value to the full path of your com.my.mpv_host.json file (e.g., C:\Users\Me\Scripts\com.my.mpv_host.json).
macOS:
Place the com.my.mpv_host.json file in: ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/
Linux:
Place the com.my.mpv_host.json file in: ~/.config/google-chrome/NativeMessagingHosts/ (or ~/.config/chromium/... for Chromium).
Restart Chrome and test it out! You should now have your own "Open Link in mpv" option in the right-click menu.
User
I proceeded with diy method on linux. The option appears but doesn't do anything.
This is what i see in the logs:
[256033:256062:0608/164626.811912:ERROR:chrome/browser/extensions/api/messaging/native_message_process_host.cc:308] Native Messaging host tried sending a message that is 1701407843 bytes long.
Assistant
Excellent, you've diagnosed the problem perfectly! That log message is the key.
Let's break down what it means and how to fix it.
The Root Cause
The error message Native Messaging host tried sending a message that is 1701407843 bytes long tells us exactly what's wrong.
The Protocol: The native messaging protocol expects communication from the host script (your Python script) back to Chrome to be in a specific format: a 4-byte number indicating the message length, followed by the message itself (as JSON).
The Problem: Your Python script launches mpv. By default, the mpv process inherits the standard output (stdout) of its parent (the Python script). mpv is very "chatty" and prints status information to stdout as it plays a video (e.g., (+) Video --vid=1..., progress updates, etc.).
The Misinterpretation: Chrome receives this text from mpv. It tries to interpret it as a valid native message. It reads the first 4 bytes of mpv's output, gets a garbage value (which translates to the absurdly large 1701407843), and immediately terminates the connection because it knows a 1.7 GB message is not valid.
In short: mpv's normal output is being accidentally sent back to Chrome, breaking the communication.
The Fix: Redirect mpv's Output
The solution is to tell the subprocess command to launch mpv but throw away its output instead of letting it bubble up to Chrome. We do this by redirecting its stdout and stderr to DEVNULL.
Here is the corrected open_in_mpv.py script.
Replace the entire content of your open_in_mpv.py with this:
#!/usr/bin/env python3importsysimportjsonimportstructimportsubprocess# On Windows, we need to set the process creation flags to hide the console window# that would otherwise pop up when we run mpv.CREATE_NO_WINDOW=0x08000000defget_message():
"""Read a message from stdin and decode it."""raw_length=sys.stdin.buffer.read(4)
ifnotraw_length:
sys.exit(0)
message_length=struct.unpack('=I', raw_length)[0]
message=sys.stdin.buffer.read(message_length).decode('utf-8')
returnjson.loads(message)
try:
url=get_message()
command= ['mpv', url]
# --- THIS IS THE CRUCIAL FIX ---# Launch mpv, but redirect its stdout and stderr to DEVNULL (a black hole).# This prevents mpv's status messages from being sent back to Chrome.ifsys.platform=="win32":
subprocess.Popen(command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
creationflags=CREATE_NO_WINDOW)
else:
subprocess.Popen(command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
exceptExceptionase:
# This logging is very useful for debugging!# Check this file if things still don't work.withopen('/tmp/mpv_chrome_host.log', 'a') asf:
# Get the full traceback for better error infoimporttracebackf.write(f"Timestamp: {datetime.datetime.now()}\n")
f.write(f"Error: {e}\n")
f.write(traceback.format_exc())
f.write("------\n")
Next Steps to Ensure it Works
After updating the Python script, follow these steps:
1. Make the Script Executable
This is a very common gotcha on Linux. The host manifest will try to execute the script, but it will fail if it doesn't have the execute permission.
Open a terminal, navigate to where you saved open_in_mpv.py, and run:
chmod +x open_in_mpv.py
2. Check the Shebang Line
The first line of the script (#!/usr/bin/env python3) tells the system to use the python3 interpreter. Make sure python3 is installed and in your system's PATH. You can check this by running which python3 in your terminal. If it returns a path, you're good.
3. Restart Chrome
You don't always need to, but it's the surest way to make Chrome re-read everything and re-establish the connection to the native host. Completely quit Chrome and reopen it.
4. Test It
Right-click on a video link and select your "Open in mpv" option. It should now launch mpv without any issues.
5. If It Still Fails...
Check your debug log file. The try...except block in the Python script is designed to catch any other errors and write them to /tmp/mpv_chrome_host.log. For example, it would log an error if it couldn't find the mpv command.
cat /tmp/mpv_chrome_host.log
This will show you if the Python script itself is encountering an error.
User
It seems to work now.
I tried this on macOS. It works when Chrome is launched from within terminal. When launched as usual, it errors with:
Unchecked runtime.lastError: Native host has exited.
With the context:
:0 (anonymous function)
Assistant
Excellent diagnosis! This is a classic and very common issue on macOS, and you've pinpointed the exact symptom that reveals the cause.
The Problem: The PATH Environment Variable
When you launch an application on macOS, its environment is inherited differently depending on how you launch it:
Launched from Terminal: When you open a terminal, it runs your shell's startup script (e.g., ~/.zshrc or ~/.bash_profile). These scripts typically configure your PATH environment variable to include locations like /opt/homebrew/bin (for Apple Silicon) or /usr/local/bin (for Intel), which is where Homebrew installs programs like mpv. When you launch Chrome from this terminal, Chrome inherits this fully-configured environment, including the correct PATH.
Launched from GUI (Dock/Finder): When you click the Chrome icon in the Dock or Applications folder, it's launched by the system's launchd process. It inherits a very minimal, default environment. This default PATH does not include the Homebrew directories.
The result:
In the terminal case, your Python script runs, calls subprocess.Popen(['mpv', ...]), the system checks the PATH, finds mpv in the Homebrew directory, and everything works.
In the GUI case, the Python script runs, calls subprocess.Popen(['mpv', ...]), the system checks the very limited PATH, cannot find mpv, and the Python script immediately fails with a FileNotFoundError.
From Chrome's perspective, it just sees that the native host process started and then immediately died, which is exactly what the Native host has exited error means.
Solution 1 (Recommended): Use the Absolute Path in the Script
This is the most direct, reliable, and self-contained fix. Instead of relying on the PATH variable, we'll tell the script exactly where to find mpv.
1. Find the full path to mpv:
Open your terminal and run:
which mpv
This will output the full path. It will likely be one of these:
/opt/homebrew/bin/mpv (if you are on an Apple Silicon Mac)
/usr/local/bin/mpv (if you are on an Intel Mac)
2. Update your open_in_mpv.py script:
Replace the line that defines the command with the full path you just found.
BEFORE:
command= ['mpv', url]
AFTER (for an Apple Silicon Mac):
command= ['/opt/homebrew/bin/mpv', url]
OR AFTER (for an Intel Mac):
command= ['/usr/local/bin/mpv', url]
Your modified try block should now look like this (using the Apple Silicon path as an example):
try:
url=get_message()
# Use the full, absolute path to the mpv executablecommand= ['/opt/homebrew/bin/mpv', url]
ifsys.platform=="win32":
# ... (rest of the script is unchanged)else:
subprocess.Popen(command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
exceptExceptionase:
# ... (logging code is unchanged)
3. Save the script and restart Chrome.
This change will now work regardless of how Chrome is launched, because you are no longer depending on the fragile PATH environment variable.
Solution 2 (Advanced): Set the Environment for GUI Apps
If you want to fix this "system-wide" for all GUI applications, you can tell macOS to add the Homebrew path to the environment for all apps launched from the GUI.
This is more complex and generally not necessary if you only need it for this one script.
The modern way to do this is with launchctl.
Open Terminal.
Run the following command, using the correct path for your Mac's architecture (/opt/homebrew/bin for Apple Silicon, /usr/local/bin for Intel). This command sets the PATH for all subsequent GUI application launches in your current login session.
# For Apple Silicon
launchctl setenv PATH "/opt/homebrew/bin:$(launchctl getenv PATH)"# For Intel
launchctl setenv PATH "/usr/local/bin:$(launchctl getenv PATH)"
To make this permanent across reboots, you need to create a Launch Agent.
Create a file at ~/Library/LaunchAgents/environment.plist.
Paste the following content into it, again, editing the path to match your system.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
<key>Label</key>
<string>my.startup.environment</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<!-- Use the correct path for your Mac -->
<string>launchctl setenv PATH "/opt/homebrew/bin:$(launchctl getenv PATH)"</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Log out and log back in, or reboot your Mac. Your GUI apps will now have the Homebrew path.
For its simplicity and reliability, I strongly recommend Solution 1.
User
I proceeded with solution 1. The script stopped reporting that 'mpv' is unaccessible.
But as seen from Chrome, the problem stays the same. mpv doesn't appear and the native host runtime error is still there.
But I see something bizarre: upon clicking on Open in mpv option, there's a macOS "playing now" button that appears, contains nothing (a blank Apple Music ui) and then disappears.
Assistant
That's a fantastic and crucial clue! The "Now Playing" widget appearing and disappearing is the smoking gun.
Here's what's happening now:
Success: Your previous fix worked. The Python script is no longer failing because it can't find mpv. It is now successfully executing /opt/homebrew/bin/mpv.
The New Problem: The mpv process itself is starting, but then immediately quitting.
The Clue: The "Now Playing" widget is controlled by a macOS system service. When mpv starts, it registers itself as a media player, which causes the widget to appear. When mpv quits a fraction of a second later, the widget disappears.
The Cause: When launched from a non-interactive context like your Python script (which is launched by Chrome), mpv sometimes fails to properly attach to the macOS WindowServer to create its video window. It doesn't find a display context it likes, so it concludes it cannot play the video and exits cleanly. Because it exits without an error, your Python script also finishes its job and exits cleanly. From Chrome's perspective, the host process simply vanished, leading to the same Native host has exited error.
The Solution: Force mpv to Create a Window
We need to give mpv a stronger hint that yes, it is absolutely supposed to run as a GUI application and create a window. We can do this with a command-line flag. We'll also add another flag for robustness.
1. Edit your open_in_mpv.py script again.
2. Modify the line that defines the command variable.
Add the --force-window and --idle=yes flags before the URL.
--force-window: This is the key. It explicitly tells mpv to create a playback window even if it thinks it can't or shouldn't. This usually solves the issue of it quitting when run from a non-terminal context.
--idle=yes: This is a great flag for robustness. It tells mpv to start up and stay running (in an idle state) even if there's nothing to play. This can prevent it from quitting immediately if there's a slight delay in resolving the URL.
Your full try block should now look something like this:
try:
url=get_message()
# Add flags to ensure a window is created and mpv stays opencommand= ['/opt/homebrew/bin/mpv', '--force-window', '--idle=yes', url]
ifsys.platform=="win32":
subprocess.Popen(command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
creationflags=CREATE_NO_WINDOW)
else:
subprocess.Popen(command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
exceptExceptionase:
# ... (logging code remains the same)
Next Steps
Save the modified open_in_mpv.py file.
Completely quit and restart Chrome. This is important to make sure any old, cached versions of the host script are gone.
Test it again by right-clicking a link.
This time, mpv should be forced to create its window, and it should launch and play the video as expected, even when Chrome is started from the Dock or Finder.
User
mpv appears now. But it's empty. The window title says "No file - mpv".
Assistant
This is progress! We are getting very close.
This symptom—mpv launching but being empty—tells us something extremely specific:
The Chrome extension, the native host registration, and the Python script are all working correctly to launch the mpv process.
The problem is that the URL is not being passed from the Python script to the mpv process. The url variable in your script is likely empty or None.
Let's find out why. We need to trace the data from Chrome to Python.
Step 1: Add Debug Logging to Your Python Script
This is the most important step. We need to see exactly what message Chrome is sending to our script.
Modify your open_in_mpv.py to log the received URL before trying to use it.
#!/usr/bin/env python3importsysimportjsonimportstructimportsubprocessimportdatetime# Import datetime for logging# ... (get_message function remains the same) ...defget_message():
"""Read a message from stdin and decode it."""raw_length=sys.stdin.buffer.read(4)
ifnotraw_length:
sys.exit(0)
message_length=struct.unpack('=I', raw_length)[0]
message=sys.stdin.buffer.read(message_length).decode('utf-8')
returnjson.loads(message)
# Define the log file pathLOG_FILE='/tmp/mpv_chrome_host.log'try:
# Get the URL sent by the extensionurl=get_message()
# --- THIS IS THE NEW DEBUGGING CODE ---# Log exactly what we received from Chromewithopen(LOG_FILE, 'a') asf:
f.write(f"--- {datetime.datetime.now()} ---\n")
f.write(f"Received URL: '{url}' (Type: {type(url)})\n")
# --- END OF DEBUGGING CODE ---# Only proceed if the URL is not emptyifurl:
command= [
'/opt/homebrew/bin/mpv', # Or /usr/local/bin/mpv for Intel'--force-window',
'--idle=yes',
url
]
subprocess.Popen(command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
exceptExceptionase:
# This will catch errors in get_message() or subprocesswithopen(LOG_FILE, 'a') asf:
importtracebackf.write(f"--- {datetime.datetime.now()} ---\n")
f.write(f"An error occurred:\n")
f.write(traceback.format_exc())
Step 2: Test and Check the Log
Save the updated Python script.
Completely quit and restart Chrome.
Right-click on a video link or a YouTube page and select "Open in mpv".
mpv will likely open empty again. That's okay.
Now, open your Terminal and check the log file:
cat /tmp/mpv_chrome_host.log
You will most likely see something like:
Received URL: '' (Type: <class 'str'>)
This would confirm that Chrome is sending an empty string to your script.
Step 3: Fix the Chrome Extension (The Likely Cause)
The issue is almost certainly in how the background.js script is capturing the URL. When you right-click on different things, Chrome provides the URL in different properties of the info object.
info.linkUrl: For <a href="..."> links.
info.srcUrl: For media elements like <video>, <img>, or <audio>. This is crucial for embedded players.
info.pageUrl: The URL of the current page. This is the fallback for sites like YouTube.
Your current background.js probably only checks for one or two of these. Let's make it robust by checking for all of them in the correct order of priority.
Replace the entire content of your background.js with this:
// The name of our native host, from its manifest file.constNATIVE_HOST_NAME="com.my.mpv_host";// Create the context menu item when the extension is installed.chrome.runtime.onInstalled.addListener(()=>{chrome.contextMenus.create({id: "open-in-mpv",title: "Open in mpv",// Make the option available on links, pages, and media elementscontexts: ["link","page","video","audio"]});});// Handle the click event.chrome.contextMenus.onClicked.addListener((info,tab)=>{if(info.menuItemId==="open-in-mpv"){// Determine the URL in order of preference:// 1. A direct link URL.// 2. The source URL of a media element (e.g., a <video> tag).// 3. The URL of the page itself (for sites like YouTube).consturl=info.linkUrl||info.srcUrl||info.pageUrl;if(url){console.log("Sending URL to native host:",url);// For debugging in the extension's consolechrome.runtime.connectNative(NATIVE_HOST_NAME).postMessage(url);}else{console.error("Could not determine a URL to send to mpv.");}}});
Final Steps to Apply the Fix
Save the new background.js file.
Go back to the Chrome Extensions page: chrome://extensions.
Find your "DIY Open in mpv" extension.
Click the reload icon (a circular arrow) on the extension's card. This forces Chrome to load the new background.js file.
Try right-clicking again. It should now work for a much wider variety of content.
This combination of better logging in the Python script and more robust URL detection in the JavaScript should solve the problem for good.
User
I added the url logging. It's there. The script knows the URL to play.
Assistant
Okay, this is a fantastic piece of information. Your debugging has successfully isolated the final link in the chain.
Let's recap what we know:
Chrome -> Python: Works. The background.js sends the URL.
Python Script: Works. The script receives the URL and logs it correctly.
Python -> mpv Launch: Works. The subprocess.Popen call successfully starts the mpv process with its window.
The fact that mpv starts but shows "No file" while your script knows the URL means mpv itself is failing to process the URL you're giving it.
The Diagnosis: The yt-dlp Helper is Missing
When you give mpv a URL from a site like YouTube, Twitch, etc., it doesn't download the video itself. It uses a helper program to extract the direct video stream URL. This helper is almost always yt-dlp (or its predecessor, youtube-dl).
This is a classic "chain of failure" problem, identical to the one we solved for mpv itself:
You launch Chrome from the GUI, so it has a minimal PATH.
Your Python script inherits this minimal PATH.
mpv is launched by Python and it also inherits the same minimal PATH.
When mpv gets the YouTube URL, it tries to execute yt-dlp to resolve it.
It looks for yt-dlp in its minimal PATH, can't find it, and gives up on the URL.
It remains open (because of --idle=yes) but has no file to play.
Quick Confirmation Test (Optional)
If you right-click on a link to a direct video file (e.g., a URL ending in .mp4 or .mkv), it will probably work perfectly. This is because mpv can handle direct file URLs without needing yt-dlp. If this test passes, the diagnosis is 100% confirmed.
The Solution: Tell mpv Where to Find yt-dlp
Just like we gave mpv its own full path, we need to give it the full path to its helper.
1. Find the full path to yt-dlp:
First, make sure it's installed (brew install yt-dlp if not). Then, find its path by running this in your terminal:
which yt-dlp
It will output something like /opt/homebrew/bin/yt-dlp (Apple Silicon) or /usr/local/bin/yt-dlp (Intel).
2. Update your open_in_mpv.py script:
We will add a special option to mpv to tell it exactly where to find the yt-dlp executable.
The mpv option is: --script-opts=ytdl_hook-ytdl_path=/path/to/your/yt-dlp
Modify the command list in your script to include this new option.
command= [
'/opt/homebrew/bin/mpv',
'--force-window',
'--idle=yes',
# Explicitly tell mpv where to find its helper utility'--script-opts=ytdl_hook-ytdl_path=/opt/homebrew/bin/yt-dlp',
url
]
Your final, fully robust try block should now look like this:
try:
url=get_message()
# Log what we receivedwithopen(LOG_FILE, 'a') asf:
f.write(f"--- {datetime.datetime.now()} ---\n")
f.write(f"Received URL: '{url}'\n")
ifurl:
# Use absolute paths for both mpv and its yt-dlp helper# to ensure it works when launched from the GUI.command= [
'/opt/homebrew/bin/mpv', # Or /usr/local/bin/mpv for Intel'--force-window',
'--idle=yes',
'--script-opts=ytdl_hook-ytdl_path=/opt/homebrew/bin/yt-dlp', # Or /usr/local/bin/yt-dlpurl
]
subprocess.Popen(command,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
exceptExceptionase:
# ... (logging code) ...
Final Steps
Save the updated open_in_mpv.py.
Completely quit and restart Chrome.
Test it on a YouTube page.
This should be the final piece of the puzzle. By removing all reliance on the inherited PATH variable for every program in the chain, you create a fully self-contained and reliable script that will work no matter how Chrome is launched.
Would be nice also to be able to pass the current page to MPV (just in case one hasn't been able to do that via a right click on the link beforehand). Seems like adding some additional context ("page"?) will suffice?
Would be nice also to be able to pass the current page to MPV (just in case one hasn't been able to do that via a right click on the link beforehand). Seems like adding some additional context ("page"?) will suffice?
@for-coursera Oh you're right, it was actually there but I decided to delete it because I couldn't see how it could be useful. I can bring it back!
@hammerill It's up to you, and certainly not a problem if you personally don't see it useful, this our discussion will anyway help those, who'd like to have it :)
Would be nice also to be able to pass the current page to MPV (just in case one hasn't been able to do that via a right click on the link beforehand). Seems like adding some additional context ("page"?) will suffice?