tvheadend, fzf and mpv

by manu

I wanted to have an easy way to fuzzy find the channel I’d like to watch from my tvheadend’s playlist. After some chit chat with Claude AI I got exactly what I wanted: A fuzzy finder for my playlist, while still being able to zap to the prev/next channel. tvheadend + fzf + mpv = ❤️

#!/usr/bin/env python3

import sys
import subprocess
import re
import os
from pathlib import Path

def parse_m3u(content):
	channels = []
	current_name = None

	for line in content.split('\n'):
		if line.startswith('#EXTINF:'):
			match = re.search(r',[^,]*$', line)
			if match:
				current_name = match.group()[1:]
		elif line.startswith('http'):
			if current_name:
				channels.append((current_name, line.strip()))
				current_name = None

	return channels

def main():
	playlist_path = str(Path.home() / "docs" / "playlist")

	# Read and parse the M3U content
	content = open(playlist_path).read()
	channels = parse_m3u(content)

	# Prepare channel names for fzf
	channel_names = '\n'.join(name for name, _ in channels)

	try:
		# Run fzf with --reverse option
		fzf = subprocess.Popen(['fzf', '--reverse'], 
							 stdin=subprocess.PIPE, 
							 stdout=subprocess.PIPE,
							 text=True)
		selected, _ = fzf.communicate(channel_names)

		# Find the index of the selected channel
		selected = selected.strip()
		for index, (name, _) in enumerate(channels):
			if name == selected:
				# Launch mpv with the original playlist file
				subprocess.run([
					'mpv',
					f'--playlist-start={index}',
					f'--playlist={playlist_path}'
				], env=dict(os.environ, DISPLAY=':0'))
				
				break

	except KeyboardInterrupt:
		sys.exit(0)

if __name__ == "__main__":
	main()