5

I am trying to figure out the best solution to tag files in GNU/Linux. This is the particular thing I am trying to achieve. I download all my movies and save them on the external SSD. I sort them in two directories: "watched" and "to_watch". However, I want to assign attributes to each movie such as (but not limited to): main actor(s), director(s), genre. That way, if I have a huge amount of files and I am in a mood to watch a movie directed by Scorsese, I can display only movies that contain a tag "scorsese".

Here are some of the requirements that I have:

  • I want the solution to be independent of my local computer being used. For example, if I take my external SSD to my friend who also has the Unix system (and installs the required solution for tags), he's computer will also be able to interpret all of the tags generated by me.
  • I want to have a CLI option.
  • If I change the file's location, the tag(s) still stays with the file.
  • I can assign multiple tags to the file.
  • I can tag a file of any format.
  • I can tag a directory as well (not only files).
6
  • You could keep your "tags" in a text file named the original filename with a ".tags" suffix. You'll have to be careful to move the .tags file along with the original. Commented Dec 18, 2021 at 19:36
  • @waltinator you know, file systems have a tool for that! Extended attributes! Commented Dec 18, 2021 at 20:05
  • Media files usually have this kind of tagging built in. Are you sure that your media don't already have the information available? Commented Dec 18, 2021 at 20:28
  • 1
    @roaima I am not sure, but even if they do I want to find a general solution to this because I can think of many scenarios where I want to tag any type of file. Commented Dec 19, 2021 at 1:33
  • @waltinator I thought of a similar solution but it is really far from elegant. Commented Dec 19, 2021 at 1:34

2 Answers 2

4

Two things:

1.

The more native way is of course to use a feature of many Unix file systems to save what is called extended attributes or just xattrs. You can query, set, modify and remove these attributes from files using the getfattr and setfattr command line programs (under Linux, don't know much about how *BSD deals with these); their man-pages should be interesting to you.

However, that's not really that useful – after all, you then have a lot of files that you somehow tagged with some information, but will need to sit on a console to try and get them out again.

So, what you actually need is not only a way of tagging files, you need something to actually do something useful with that information, manage it and so forth.

2.

What you describe is functionally a movie database, and as such, probably a media server is the most useful solution. If you can restrict the number of possible platforms to one (or maybe two) like x86_64 (and maybe arm64?), you could also just put a container on your external hard drive that just contains all that is needed to run the movie database software. So your friend can just start that (don't know what shape something like that takes – maybe a DLNA server?). I've got no experience with such things.

So, what I'd do, is actually sit down and write the software you want. Sounds crazy, but is quite OK, considering any modern PC-style hardware with a Unix on it will have access to some halfway modern Python3.

3.

As described above, you could use extended file system attributes to store the information about the file – within the file "filesystem entry" itself. That way it stays with the file when you move that on the drive.

However, since, as you said, you might want to run some kind of GUI/TUI from the external drive, anyways, there's not that much benefit to that. So, a simple SQLite database (sqlite3 comes with every Python installation) would do just fine. Then, you'd just write a short tool to look for the database file, look for the media files relative to that, then add some functions to scan for files that aren't yet part of the database, add them, maybe query from IMDB's API. Of course, a nice query interface would be nice, as well, so you could either go for "text adventure" style, or you could use Textual (new, exciting, probably a bit experimental) or urwid; both are pure Python, if I'm not mistaken, so running things should be trivial on different machines!

2
  • 1
    Thank you for taking the time to suggest a solution. I will look into it and try to make it work especially with Option 1. I have also found this: github.com/oniony/TMSU and I might consider it. Commented Dec 19, 2021 at 1:38
  • 1
    @Vladimir yeah, that TMSU seems to be roughly what my "3." is! If you're planning to ship your media with software anyway, there's nicer things optimized for media storage/discovery, though I'm not much of a user of such. Commented Dec 19, 2021 at 11:04
2

I propose here a solution to easily tag files, search them and edit tags.

After searching the web, as of August 2024 there doesn't seem to be actively maintained software that allows to have a tagging files ystem on any linux distribution (a promising one was TMSU, but like other pieces of software, the last commit on the repo is several years old).

So extended attributes (xattrs) might indeed be a future-robust enough way of achieving this.

So here is my solution. In short, it amounts to simply use the setfattr and getfattr commands, via command aliases to ease the tagging, searching, removing, ensuring consistency of tags: addtag, findtag, removetag, cleantag (some of them may only work with Zsh, but Bash compatibility is attempted whenever possible).

Note: I suggest using the user.xdg.tags namespace of xattrs to tag files or directories, since it seems to be the standard in many applications for user tags (see ArchWiki: User extended attributes).

Tagging files

To tag myfile with mytag1 and mytag2, we simply append the value of user.xdg.tags to mytag1,mytag2, by comma-separating the new tags. The below command is used like so:

addtag mytag1 mytag2 myfile
function addtag()
{ ## Add tag(s) to file.
    ## The specified tags are appended to the comma-separated string value of the user.xdg.tags namespace of extended attributes.
    ## Usage: addtag TAG [...] FILE
    tags_existing=$(getfattr -n user.xdg.tags --only-value "$argv[-1]")
    setfattr -n user.xdg.tags -v "${tags_existing},${(%j:,:)argv[1,-2]}" "$argv[-1]"
}

Searching files by tags

Below is a useful shell alias to find files or directories that have at least one of the specified tags (Version 1) or all the specified tags (Version 2). This assumes the tags are values of user.xdg.tags.

Version 1: Files matching any of the specified tags

For example, to find all files/directories from the current path that have a tag containing the string str1 or-inclusive a tag containing the string str2:

findtag str1 str2 ./
  • In Bash:
    function findtag()
    { # Search for tags in the user.xdg.tags namespace of extended attributes.
      # Usage: findtag TAG [...] PATH
      local IFS="|"
      find "$*[-1]" -exec getfattr -n user.xdg.tags '{}' \+ 2>/dev/null | grep -Ei "${*[1,-2]}"
    }
  • In Zsh:
    function findtag()
    { # Search for tags in the user.xdg.tags namespace of extended attributes.
      # Usage: findtag TAG [...] PATH
      find "$argv[-1]" -exec getfattr -n user.xdg.tags '{}' \+ 2>/dev/null | grep -B 1 -Ei "${(%j:|:)argv[1,-2]}"
}

The only difference between the Bash and the Zsh version is the code to process the user-provided tags.

Version 2: Files matching all the specified tags

For example, to find all files/directories from the current path that have a tag containing the string str1 and a tag containing the string str2:

findtag str1 str2 ./

Warning: Zsh assumed.

    function findtag()
    { # Search for tags in the user.xdg.tags namespace of extended attributes.
      # Usage: findtag TAG [...] PATH
    find "$argv[-1]" -exec getfattr -n user.xdg.tags '{}' \+ 2>/dev/null | grep -B 1 -Pi "(?<=user.xdg.tags=\")(?=.*${(%j:)(?=.*:)argv[1,-2]})"
}

Cleaning tags

This shell alias allows to avoid duplicate tags, or unwanted commas between tags in the tag string. This assumes the tags are values of user.xdg.tags.

Warning: Zsh assumed.

function cleantag()
{ ## Clean the tag string of file(s).
    ## Tags are assumed to be substrings of the value of the user.xdg.tags extended attributes namespace.
    ## Usage: cleantag FILEPATH
    local tags_existing file
    for file in "$@"; do
    if getfattr -n user.xdg.tags --only-value $file &>/dev/null; then
        tags_existing=$(getfattr -n user.xdg.tags --only-value $file)
        tags_existing=${tags_existing//,,##/,} # Removing duplicate commas.
        tags_existing=$(echo "$tags_existing" | tr ',' '\n' | sort -u | tr '\n' ',') # Removing duplicate tags.
        tags_existing=${tags_existing/#,/}     # Removing leading comma.
        tags_existing=${tags_existing/%,/}     # Removing trailing comma.
        setfattr -n user.xdg.tags -v "${tags_existing}" $file
    fi
    done
}

Removing tags

This shell alias allows to remove individual tags. This assumes the tags are values of user.xdg.tags.

Warning: Zsh assumed.

function removetag()
{ ## Remove tag(s) from file.
    ## The specified tags are removed from the comma-separated string value of the user.xdg.tags extended attributes namespace.
    ## Usage: removetag TAG [...] FILEPATH
    local tags_remaining tag
    setopt localoptions extendedglob
    if getfattr -n user.xdg.tags --only-value "$argv[-1]" &>/dev/null; then
    tags_remaining=$(getfattr -n user.xdg.tags --only-value "$argv[-1]")
    for tag in "$@[1,-2]"; do
        tags_remaining=${tags_remaining//$tag/}
        echo "Tag \"${tag}\" and its duplicates were removed."
    done
    tags_remaining=${tags_remaining//,,##/,} # Removing duplicate commas.
    tags_remaining=${tags_remaining/#,/}     # Removing leading comma.
    tags_remaining=${tags_remaining/%,/}     # Removing trailing comma.
    setfattr -n user.xdg.tags -v "${tags_remaining}" "$argv[-1]"
    fi
}
3
  • Are there any gui file browsing tools or file managers that con work with this system? Commented Apr 30 at 12:58
  • @Cestarian That would indeed make this system much more intuitive, for example a view similar to the file manager, were it tags could be set/unset with mouse clicks. However a developer would be needed to implement this (NB: the above functions can probably be easily implemented in Python). Commented Apr 30 at 19:23
  • Apart from the GUI, a very useful feature in my opinion would be the ability to automatically be prompted for entering tags to a file at the moment when it is added to the file system (e.g., when a file has just been downloaded). That would make this scheme systematic (all files could be systematically tagged), potentially making it a true alternative to the folder-type file organization. But no idea how to do it. Commented Apr 30 at 19:24

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.