13

Running Ubuntu Gnome.

I have a lot of PDF and other documents and I will like to tag them. And search them later based on these tags. Even if I move the files to different folders (so, the tags stick to the files).

I searched but Files and Documents do not provide this options.

Am I doing something wrong? How can I tag files so I can search them based on tags later?

  • For only the adding tags to PDF documents part of the question (but not the searching tags part of the question) see this answer – karel Sep 21 '16 at 5:15
  • Would you consider "bookmarking" a file as option instead of tagging ? – Sergiy Kolodyazhnyy Sep 21 '16 at 15:57
  • @Serg I'm not clear. Can you explain a bit? Can these bookmarks have tags like Firefox bookmarks? Will they remain even if I move the file? – deshmukh Sep 22 '16 at 7:09
  • @deshmukh Here's what I've done before: askubuntu.com/q/803644/295286 Basically it creates a symlink to file inside a folder. On the other hand, I could implement sort of list of tags, and for each tag there would be list of files. Currently I'm somewhat busy, so it takes me forever to respond, but I will try to put out the answer ASAP. Would it be possible to put the bounty again once this one times out ? – Sergiy Kolodyazhnyy Sep 30 '16 at 20:47
  • @Serg I am not rich enough to offer another bounty :) But if this one goes without anybody winning it (is that even possible?) and if your answer (when it comes) is the best, sure, I will offer the bounty to you :) :) – deshmukh Oct 1 '16 at 6:04
7
+25

Contents:

  1. Introduction
  2. Installation
  3. Usage
  4. Source code

1. Introduction

This solution consists of two scripts - one for tagging, one for reading the list of files under specific tag. Both have to live in ~/.local/share/nautilus/scripts and activated via right-click in Nautilus file manager on any file, and navigating to Scripts submenu. The source code for each script is provided here as well as on GitHub

2. Installation

Both scripts have to be saved to ~/.local/share/nautilus/scripts , where ~ is user's home directory, and made executable with chmod +x filename. For easy installation, use the following bash script:

#!/bin/bash

N_SCRIPTS="$HOME/.local/share/nautilus/scripts"
cd /tmp
rm master.zip*
rm -rf nautilus_scripts-master
wget https://github.com/SergKolo/nautilus_scripts/archive/master.zip
unzip master.zip
install nautilus_scripts-master/tag_file.py "$N_SCRIPTS/tag_file.py"
install nautilus_scripts-master/read_tags.py "$N_SCRIPTS/read_tags.py"

3. Usage:

Tagging files:

Select files in Nautilus file manager, right click on them, and navigate to Scripts submenu. Select tag_file.py. Hit Enter enter image description here First time you run this script, there will be no configuration file, so you will see this:

enter image description here

Next time, when you already have some files tagged, you will see a popup that allows you to select a tag and/or add new one ( this way you can record files under multiple tags). Hit OK to add files to this tag. Note:Avoid having "|" symbol in the tag name.

enter image description here

The script records everything in ~/.tagged_files. That file is essentially a json dictionary ( which is not something regular users should care about, but it's convenient for programmers :) ). The format of that file is as so:

{
    "Important Screenshots": [
        "/home/xieerqi/\u56fe\u7247/Screenshot from 2016-10-01 09-15-46.png",
        "/home/xieerqi/\u56fe\u7247/Screenshot from 2016-09-30 18-47-12.png",
        "/home/xieerqi/\u56fe\u7247/Screenshot from 2016-09-30 18-46-46.png",
        "/home/xieerqi/\u56fe\u7247/Screenshot from 2016-09-30 17-35-32.png"
    ],
    "Translation Docs": [
        "/home/xieerqi/Downloads/908173 - \u7ffb\u8bd1.doc",
        "/home/xieerqi/Downloads/911683\u7ffb\u8bd1.docx",
        "/home/xieerqi/Downloads/914549 -\u7ffb\u8bd1.txt"
    ]
}

If you ever want to "untag" some file, just delete an entry from that list. Mind the format and commas.

Searching by tag:

Now that you have a nice ~/.tagged_files database of files, you can either read that file, or use read_tags.py script.

Right click on any file in Nautilus ( really doesn't matter which ).Select read_tags.py. Hit Enter enter image description here

You will see a popup asking you what tag you want to search:

enter image description here

Select one, click OK. You will see a list dialog showing you want files are there for the tag you selected. You can select any single file and it will open with a default program assigned to that file type.

enter image description here

4. Source code:

tag_file.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Author: Serg Kolo  
# Date: Oct 1st, 2016
# Description: tag_file.py, script for
#    recording paths to files under 
#    specific , user-defined tag
#    in ~/.tagged_files
# Written for: http://askubuntu.com/q/827701/295286
# Tested on : Ubuntu ( Unity ) 16.04

from __future__ import print_function
import subprocess
import json
import os
import sys

def show_error(string):
    subprocess.call(['zenity','--error',
                     '--title',__file__,
                     '--text',string
    ])
    sys.exit(1)

def run_cmd(cmdlist):
    """ Reusable function for running external commands """
    new_env = dict(os.environ)
    new_env['LC_ALL'] = 'C'
    try:
        stdout = subprocess.check_output(cmdlist, env=new_env)
    except subprocess.CalledProcessError:
        pass
    else:
        if stdout:
            return stdout


def write_to_file(conf_file,tag,path_list):

    # if config file exists , read it
    data = {}
    if os.path.exists(conf_file):
        with open(conf_file) as f:
            data = json.load(f)

    if tag in data:
        for path in path_list:
            if path in data[tag]:
               continue
            data[tag].append(path)
    else:
        data[tag] = path_list

    with open(conf_file,'w') as f:
        json.dump(data,f,indent=4,sort_keys=True)

def get_tags(conf_file):

    if os.path.exists(conf_file):
       with open(conf_file) as f:
            data = json.load(f)
            return '|'.join(data.keys())

def main():

    user_home = os.path.expanduser('~')
    config = '.tagged_files'
    conf_path = os.path.join(user_home,config)
    file_paths = [ os.path.abspath(f) for f in sys.argv[1:] ]
    tags = None

    try:
        tags = get_tags(conf_path)
    except Exception as e:
        show_error(e)

    command = [ 'zenity','--forms','--title',
                'Tag the File' 
    ]

    if tags:
       combo = ['--add-combo','Existing Tags',
                '--combo-values',tags
       ]

       command = command + combo

    command = command + ['--add-entry','New Tag']

    result = run_cmd(command)
    if not result: sys.exit(1)
    result = result.decode().strip().split('|')
    for tag in result:
        if tag == '':
           continue
        write_to_file(conf_path,tag,file_paths)

if __name__ == '__main__':
     main()

read_tags.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Author: Serg Kolo  
# Date: Oct 1st, 2016
# Description: read_tags.py, script for
#    reading  paths to files under 
#    specific , user-defined tag
#    in ~/.tagged_files
# Written for: http://askubuntu.com/q/827701/295286
# Tested on : Ubuntu ( Unity ) 16.04

import subprocess
import json
import sys
import os


def run_cmd(cmdlist):
    """ Reusable function for running external commands """
    new_env = dict(os.environ)
    new_env['LC_ALL'] = 'C'
    try:
        stdout = subprocess.check_output(cmdlist, env=new_env)
    except subprocess.CalledProcessError as e:
        print(str(e))
    else:
        if stdout:
            return stdout

def show_error(string):
    subprocess.call(['zenity','--error',
                     '--title',__file__,
                     '--text',string
    ])
    sys.exit(1)

def read_tags_file(file,tag):

    if os.path.exists(file):
       with open(file) as f:
            data = json.load(f)
            if tag in data.keys():
                return data[tag]
            else:
                show_error('No such tag')
    else:
       show_error('Config file doesnt exist')

def get_tags(conf_file):
    """ read the tags file, return
        a string joined with | for
        further processing """    
    if os.path.exists(conf_file):
       with open(conf_file) as f:
            data = json.load(f)
            return '|'.join(data.keys())

def main():

    user_home = os.path.expanduser('~')
    config = '.tagged_files'
    conf_path = os.path.join(user_home,config)

    tags = get_tags(conf_path)
    command = ['zenity','--forms','--add-combo',
               'Which tag ?', '--combo-values',tags
    ]

    tag = run_cmd(command)

    if not tag:
       sys.exit(0)

    tag = tag.decode().strip()
    file_list = read_tags_file(conf_path,tag)
    command = ['zenity', '--list', 
               '--text','Select a file to open',
               '--column', 'File paths'
    ]
    selected = run_cmd(command + file_list)    
    if selected:
       selected = selected.decode().strip()
       run_cmd(['xdg-open',selected])

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        show_error(str(e))

  • this is cool. you always have the most interesting solutions. – user383919 Oct 2 '16 at 3:13
  • @jargonjunkie thank you for the kind words :) – Sergiy Kolodyazhnyy Oct 2 '16 at 3:22
  • @Serg this is wonderful. Will the tags stick when I move the files? Or when I delete the files, will they still show in the search results? – deshmukh Oct 2 '16 at 15:12
  • @deshmukh No, the tags don't stick if you move the files, and deleted files do show up. I could implement checking for deleted files ( quite easily actually, it's just a few lines ). Essentially you have a database of tags and their files, ans this database has to be maintained – Sergiy Kolodyazhnyy Oct 2 '16 at 17:50
  • @Serg we are so near yet so far. Because unless the tags kind of 'stick' to the files (so they remain even after moving the file around), it is as good or as bad as a hierarchical directory structure except that one file can have multiple tags. I am not, even for a moment, belittling your excellent work. I am only saying that it still does not address my (may be, crazy) needs. Also, as jargonjunkie said in a separate comment, may be tagging the files directly could be the solution (like we tag photographs or bookmarks). But these are words of a novice. – deshmukh Oct 3 '16 at 5:34
0

I have found a way to do this.

Open a terminal (CTRL+ALT+T) and then run this command:

sudo add-apt-repository ppa:tracker-team/tracker

Enter your password, and when Prompted, press enter, then run

sudo apt-get update

then

sudo apt-get install tracker tracker-gui

Don't worry if it says it's already the latest version.

Now open Nautilus/Files and right click the document you want to add tags to. Select properties, then select the tab that says "Tags". Enter a tag into the text box and press enter or click the Add button to add it. You can also click a tag you have already added and select the Remove button to remove a tag. Please note that tags are case sensitive. The tags you create will be persistent throughout the system, so you can easily put a check next to a tag you already created to mark the file instead of manually typig it again.

After tagging the items wanted, you can now search for them, but not in Files. Go to activities, and search for the app Desktop Search. Launch it, and look at the options at the top. At the top left side of the Window, click the folder icon with the tool tip "Display results by files in a list". Now you have more options. Select the option just to the left of the search box with the tool tip "Find search criteria in file tags only". Now you can search tags!

To use this, enter the tags you want to search, seperated by commas and press enter. For example:

Important, September, Presentation

This will only show files which have all three tags: "Important", "September", and "Presentation".

By double clicking one, it will open the file in the default program, and by right clicking and selecting "Show Parent Directory", it will open it's location in Nautilus.

In Desktop Search, you can also click the second button from the right at the top of the window (usually a star or heart) to edit tags in the app itself!

There you have it! Hope this helps. If you have any more questions, let me know.

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.