#!/usr/bin/python3 """Tag query. The idea is something like `tq mpv chill -lyrics`, looking in `chill.playlist` and `lyrics.playlist` to see if `foo.mp3` is in one but not the other, passing it to `mpv` if so. This approach to storing tag data is of limited efficiency; on my laptop it reads about 500 000 items per second from a single tag file, or about 20 megabytes per second, whichever is slower, and only up to about 9000 different tags per second. This may, however, be adequate performance for many purposes. For example, with a 16-millisecond deadline, you can evaluate up to 8000 tag-item pairs totaling up to 320 kilobytes from up to 144 different tags. In practice, this probably means that you can have up to a few tens of thousands of distinct items tagged before the system starts to get slow. """ import os import sys import subprocess def tagquery(terms): for i, term in enumerate(terms): if not term.startswith('-'): cur = read(term) terms = terms[:i] + terms[i+1:] break else: # All negative query; assume universe is `.` cur = set(os.listdir('.')) for term in terms: cur = cur - read(term[1:]) if term.startswith('-') else cur & read(term) return cur def read(tag): if not tag.endswith('.playlist'): tag = '{}.playlist'.format(tag) with open(tag) as f: return set(line[:-1] if line.endswith('\n') else line for line in f) # Notes on improving UI for tagging: # I figured you could run lsof to find out what the currently playing # song or whatever was, and have a `tag` program to add whatever.mp4 to # foo.playlist and bar.playlist. # lsof output looks like this, which is probably adequate to guess: # mpv 9366 user 8r REG 252,1 69018724 1576876 /home/user/Downloads/music/Blue Man Group - NPR Music Tiny Desk Concert-qTJfITfbYNA.mp4 # mpv 9366 user 9r FIFO 0,10 0t0 110933 pipe # mpv 9366 user 10w FIFO 0,10 0t0 110933 pipe # mpv 9366 user 11u unix 0x0000000000000000 0t0 110934 type=STREAM # mpv 9366 user 12u CHR 226,0 0t0 353 /dev/dri/card0 # mpv 9366 user 13r FIFO 0,10 0t0 110944 pipe if __name__ == '__main__': subprocess.run([sys.argv[1]] + list(tagquery(sys.argv[2:])))