Page 4 of 4 FirstFirst ... 234
Results 31 to 38 of 38

Thread: Extracting data from recently-used.xbel?

  1. #31
    Join Date
    Sep 2020
    Beans
    9

    Re: Extracting data from recently-used.xbel?

    Hey geoff, I have figured a workaround for a system-wide refresh shortcut! I'm aware you may view it as a total bloody mess - but at least you can spare the work for this.

    First off, I named your script 'recentfolders' and put it in a dedicated folder along with a .sh file in which i wrote:

    cd /media/user/.../folder_name
    if pgrep -x "python3" > /dev/null
    then
    pkill python3 && python3 script_name
    else
    python3 recentfolders
    fi

    (If Python is running, then it kills the process and re-opens the script; otherwise it simply opens it. Of course, this only works if it's the only Python script running.) Then, in the menu editor, I created a launcher which pointed to the .sh file. And finally, I created a new keyboard shortcut pointing towards that launcher I found in ~/.local/share/applications using the gtk-launch command.

    However, for the other thing radio buttons would really be perfect. Would the default choice be easy to code so it stays? I managed to make the folders open with nemo in your script and am pretty stoked about this too.
    Last edited by erza-k-rot; 4 Weeks Ago at 01:52 PM.

  2. #32
    Join Date
    Aug 2018
    Location
    England
    Beans
    51
    Distro
    Xubuntu

    Re: Extracting data from recently-used.xbel?

    A better solution than a refresh button is to refresh the display whenever the window gains focus. This little script illustrates the process.

    Code:
    from tkinter import *
    def handle_focus(event):
        if event.widget == root:
            listbox.insert(END, 'X')root = Tk()
    
    listbox = Listbox(root)
    listbox.pack()
    
    entry = Entry(root)
    entry.pack()
    
    root.bind("<FocusIn>", handle_focus)
    
    root.mainloop()
    This script adds an 'X' to the listbox every time the window gains focus. I can keep the MaxDays text box and apply the date filter on the first pass through the .xbel file.

  3. #33
    Join Date
    Aug 2018
    Location
    England
    Beans
    51
    Distro
    Xubuntu

    Re: Extracting data from recently-used.xbel?

    I have modified the program so that the list of paths is refreshed whenever the window gains focus.

    Code:
    import os
    from xml.dom import minidom
    from collections import namedtuple
    from datetime import date
    from dateutil import parser
    import urllib.parse
    import subprocess
    from tkinter import *
    
    # Do not show paths that were modified more than MaxDays before today.
    MaxDays = 90
    
    # Named tuple for storage of path name + date entries.
    pathdate = namedtuple('pathdate',['path','date'])
    
    # Pruned list of path names and dates extracted from the .xbel file.
    Pruned = []
    
    # Event handler for the root window gaining focus.
    def handle_focus(event):
        if event.widget == root:
            fill_listbox()
    
    # Event handler for a left mouse click on a list box entry.
    def on_click_listbox(event):
        global pruned
        # Get the selected line index tuple.
        index = listbox.curselection()
        # Open Thunar with the selected path name.
        subprocess.Popen(['thunar', Pruned[index[0]].path])
    
    # Event handler for <CR> in the entry field.
    def on_return_entry(event):
        global MaxDays
        try:
            MaxDays = int(event.widget.get())
        except:
            entry.delete(0, END)
            entry.insert(0, 'Error')
        fill_listbox()
    
    # Event Handler for ^q=quit
    def finish(event):
        quit()
        
    # Create the root window.
    root = Tk()
    root.title("Recently Accessed Folders")
    # Bind the window gaining focus event to handle.focus
    root.bind("<FocusIn>", handle_focus)
    # Bind Ctrl-q to finish
    root.bind('<Control-q>',finish)
    
    # Create a Frame at the bottom of the root window.
    frame = Frame(root)
    frame.pack(side=BOTTOM)
    
    # Create a text label on the left of the Frame.
    label = Label(frame, text='Maximum days folder accessed before today')
    label.pack(side=LEFT)
    
    # Create an entry field on the right of the Frame.
    entry = Entry(frame, width=5)
    entry.insert(0, str(MaxDays))
    entry.bind('<Return>', on_return_entry)
    entry.pack(side=RIGHT)
    
    # Create a Listbox and attach it to the left side of the root window.
    listbox = Listbox(root, height = 30, width = 60)
    listbox.pack(expand=True, side = LEFT, fill = BOTH)
    
    # Create a Scrollbar and attach it to the right side of the root window.
    scrollbar = Scrollbar(root)
    scrollbar.pack(side = RIGHT, fill = Y)
    scrollbar.config(command = listbox.yview)
        
    # Attach the Listbox to the Scrollbar.
    listbox.config(yscrollcommand = scrollbar.set)
    
    # Bind a left mouse click event and a Return key to the listbox. 
    listbox.bind('<ButtonRelease-1>', on_click_listbox)
    listbox.bind('<Return>',on_click_listbox)
    listbox.focus_set()
    
    def fill_listbox():
        
        global MaxDays, Pruned
        
        # Extract the directory path names and modification dates from the recently-used.xbel file.
        mydom=minidom.parse(os.environ['HOME'] + '/.local/share/recently-used.xbel')
        bookmarkNodeList=mydom.getElementsByTagName('bookmark')
        PathDates = []
        for bookmarkNode in bookmarkNodeList:
            filepath=bookmarkNode.getAttribute('href')
            moddate=bookmarkNode.getAttribute('modified')
            fp=urllib.parse.unquote(filepath)[7:]
            if os.path.exists(fp):
                # Use the parser from dateutils to get a datetime from the timestamp string,
                # and then turn that into a date.
                Date = parser.parse(moddate).date()
                if (date.today() - Date).days <= MaxDays:
                    PathDates.append(pathdate(os.path.dirname(filepath), Date))
    
        # Sort PathDates into descending order of path and then modification date.
    
        # Sort needs a function to give it a key because the list contains complex elements.
        def pd_keyfunc(item):
            return item.path + item.date.strftime("%Y-%m-%d")
    
        PathDates.sort(reverse=True,key=pd_keyfunc)
    
        # Each group of duplicate paths is now together in the list, in descending order of date.
        # For each group of duplicate paths, select the first entry for each path from the list,
        # which will be the one with the most recent date.
        Pruned = []
        PrevPath = ''
        for row in PathDates:
            if row.path != PrevPath:
                Pruned.append(row)
                PrevPath = row.path
    
        # Sort Pruned into descending order of date.
    
        # Sort needs a function to give it a key because the list contains complex elements.
        def p_keyfunc(item):
            return item.date
    
        Pruned.sort(reverse=True,key=p_keyfunc)
    
        # Fill the listbox with the path names with special characters. 
        listbox.delete(0, END)
        for row in Pruned:
            listbox.insert(END, urllib.parse.unquote(row.path[7:]))
    
    root.mainloop()
    I have had to restructure the program, and it is looking tidier now. I have removed the setting of the list box size based on the maximum path length with the default setting for MaxDays. If we that keep refinement, we should dynamically resize whenever the value of MaxDays changes. I am not sure that is a good idea. I have fixed the problem that partly motivated that change. The scrollbar used to separate from the list box when the window size was increased. That is fixed by using side=LEFT for the scrollbar rather than side=RIGHT. I copied that mistake from a tutorial on Geeks for Geeks.
    Last edited by geofftf; 4 Weeks Ago at 09:36 AM. Reason: Redundant refresh

  4. #34
    Join Date
    Sep 2020
    Beans
    9

    Re: Extracting data from recently-used.xbel?

    This is dangerously approaching perfection there geoff; I certainly think more than a few people will find this helpful. The refresh works amazingly! I really want to thank you for this, it's helping my xubuntu's ergonomy tremendously and I've learned a lot along the way too. I'm still strongly tempted to take you up on your offer to program some radio buttons, but I hope it's not too much to ask! Let me know.

    EDIT: I just noticed folders are not sorted by date anymore, is it the same for you?
    Last edited by erza-k-rot; 4 Weeks Ago at 04:33 PM.

  5. #35
    Join Date
    Aug 2018
    Location
    England
    Beans
    51
    Distro
    Xubuntu

    Re: Extracting data from recently-used.xbel?

    Yes, I will put in radio buttons: "Show Folders" and "Show Paths", with Folders as the default. I will also include a checkbox "Show Dates".

    I have just checked, and my paths are sorted into descending order of date. You can check that by changing the listbox.insert at (almost) the end of the program to:

    listbox.insert(END, row.date.strftime("%Y-%m-%d ") + urllib.parse.unquote(row.path[7:]))

    That will add the modification date to the beginning of each row.

  6. #36
    Join Date
    Aug 2018
    Location
    England
    Beans
    51
    Distro
    Xubuntu

    Re: Extracting data from recently-used.xbel?

    I have added radio buttons and a check box:

    Code:
    # This Python3 program reads the recently-used.xbel file. It extracts the
    # directory path names and modification dates. The folder or path names
    # (and optionally modification dates) are displayed in a list box.
    # The user can select list box entries using either the mouse or the keyboard.
    # Thunar is launched each time the user makes a selection.
    # The list box entries are refreshed whenever the window gains focus.
    # The user can a set a filter for the time window within which entries are
    # displayed.
    
    import os
    from xml.dom import minidom
    from collections import namedtuple
    from datetime import date
    from dateutil import parser
    import urllib.parse
    import subprocess
    from tkinter import *
    import tkinter.messagebox
    
    # Do not show paths that were modified more than MaxDays before today.
    MaxDays = 30
    
    # Named tuple for storage of path name + date entries.
    pathdate = namedtuple('pathdate',['path','date'])
    
    # Pruned list of path names and modification dates extracted from the .xbel file.
    Pruned = []
    
    # Initialise the listbox display options.
    show_paths = show_dates = False
    
    # Event handler for the window gaining focus.
    def handle_focus(event):
        if event.widget == root: fill_listbox()
    
    # Event handler for Return in the entry field.
    def on_return_entry(event):
        global MaxDays
        try:
            MaxDays = int(event.widget.get())
        except:
            tkinter.messagebox.showerror('Error', 'Must be an integer')
        fill_listbox()
        
    # Event handler for a radio button selection: "Show Folders" or "Show Paths".
    def on_radio_select():
        global show_paths
        show_paths = RadioVar.get()
        fill_listbox()
    
    # Event handler for a check button selection or deselection of "Show Dates".
    def on_checkbutton_click():
        global show_dates
        show_dates = CheckVar.get()
        fill_listbox()
    
    # Event handler for a left mouse click on a list box entry.
    def on_click_listbox(event):
        # Get the selected line index tuple.
        index = listbox.curselection()
        # Open Thunar with the selected path name.
        subprocess.Popen(['thunar', Pruned[index[0]].path])
    
    # Event Handler for <Ctrl q>.
    def finish(event):
        quit()
        
    # Create the root window.
    root = Tk()
    root.title("Recently Accessed Folders")
    # Bind the window gaining focus event to handle.focus
    root.bind("<FocusIn>", handle_focus)
    # Bind <Ctrl q> to finish
    root.bind('<Control-q>',finish)
    
    # Create a frame at the bottom of the root window.
    frame1 = Frame(root, bd=4)
    frame1.pack(side=BOTTOM)
    
    # Create a text label on the left of the Frame.
    label = Label(frame1, text='Maximum days folders accessed before today')
    label.pack(side=LEFT)
    
    # Create an entry field on the right of the Frame.
    entry = Entry(frame1, width=5)
    entry.insert(0, str(MaxDays))
    entry.bind('<Return>', on_return_entry)
    entry.pack(side=RIGHT)
    
    # Create a frame at the bottom of the remaining space within the root window.
    frame2 = Frame(root, bd=6)
    frame2.pack(side=BOTTOM)
    
    # Create a radio button group with the options "Show Folders" and "Show Paths".
    RadioVar = BooleanVar()
    radio1 = Radiobutton(frame2, text='Show Folders', variable=RadioVar,
        value=False, command=on_radio_select)
    radio1.pack(side=LEFT)
    radio2 = Radiobutton(frame2, text='Show Paths', variable=RadioVar,
         value=True, command=on_radio_select)
    radio2.pack(side=LEFT)
    RadioVar.set(False)
    
    # Create a check box to show the modification date for each row in the listbox.
    CheckVar = BooleanVar()
    check_button = Checkbutton(frame2, text='Show Dates', variable=CheckVar,
        onvalue=True, offvalue=False, width=15, command=on_checkbutton_click)
    check_button.pack(side=LEFT)
    
    # Create a listbox and attach it to the left side of the root window.
    listbox = Listbox(root, height = 30, width = 70)
    listbox.pack(expand=True, side = LEFT, fill = BOTH)
    
    # Create a Scrollbar and attach it to the right side of the root window.
    scrollbar = Scrollbar(root)
    scrollbar.pack(side = RIGHT, fill = Y)
    scrollbar.config(command = listbox.yview)
        
    # Attach the listbox to the Scrollbar.
    listbox.config(yscrollcommand = scrollbar.set)
    
    # Bind a left mouse click event and the Return key to the listbox. 
    listbox.bind('<ButtonRelease-1>', on_click_listbox)
    # Bind the Retuen key to the currently selecetd entry in the listbox.
    listbox.bind('<Return>', on_click_listbox)
    
    def fill_listbox():
        
        global MaxDays, Pruned, show_paths, show_dates
        
        # Extract the directory path names and modification dates
        # from the recently-used.xbel file.    
        mydom=minidom.parse(os.environ['HOME'] + '/.local/share/recently-used.xbel')
        bookmarkNodeList=mydom.getElementsByTagName('bookmark')
        PathDates = []
        for bookmarkNode in bookmarkNodeList:
            filepath=bookmarkNode.getAttribute('href')
            moddate=bookmarkNode.getAttribute('modified')
            fp=urllib.parse.unquote(filepath)[7:]
            if os.path.exists(fp):
                # Use the parser from dateutils to get a datetime from the
                # timestamp string, and turn that into a date.
                Date = parser.parse(moddate).date()
                if (date.today() - Date).days <= MaxDays:
                    PathDates.append(pathdate(os.path.dirname(filepath), Date))
    
        # Sort PathDates into descending order of path and then modification date.
    
        def pd_keyfunc(item):
            return item.path + item.date.strftime("%Y-%m-%d")
    
        PathDates.sort(reverse=True,key=pd_keyfunc)
    
        # Each group of duplicate paths is now together in the list, in descending
        # order of date. For each group of duplicate paths, select the first entry
        # for each path from the list, which will be the one with the most recent
        # date.
        Pruned = []
        PrevPath = ''
        for row in PathDates:
            if row.path != PrevPath:
                Pruned.append(row)
                PrevPath = row.path
    
        # Sort the pruned list into descending order of date.
    
        def p_keyfunc(item):
            return item.date
    
        Pruned.sort(reverse=True,key=p_keyfunc)
    
        # Fill the listbox.
        listbox.delete(0, END)
        for row in Pruned:
            if show_dates:
                outstr = ' ' + row.date.strftime("%Y-%m-%d") + '    '
            else:
                outstr = ' '
            path_name = urllib.parse.unquote(row.path[7:])
            folder_name = path_name[path_name.rindex('/')+1:]
            outstr = outstr + (path_name if show_paths else folder_name)
            listbox.insert(END, ' ' + outstr)
        
        # Set the focus to the listbox.
        listbox.focus_set()
        # Select the first line of the listbox (for <CR>).
        listbox.select_set(0)
    
    root.mainloop()
    I have also fixed a problem with keyboard selection. The program crashed if the Return key was hit before making a selection with the up an down arrow keys. Xfce does not appear to support keyboard navigation. Neither does Thunar.

  7. #37
    Join Date
    Sep 2020
    Beans
    9

    Re: Extracting data from recently-used.xbel?

    Yesss this is astonishing! Just great great stuff!

    I played around with the window size a little bit, opened with nemo by default, and I added the time to this line so they would be displayed by time order:
    return item.path + item.date.strftime("%Y-%m-%d, %H:%M:%S")

    I could never thank you enough for your help. You are a very cool person

  8. #38
    Join Date
    Aug 2018
    Location
    England
    Beans
    51
    Distro
    Xubuntu

    Re: Extracting data from recently-used.xbel?

    Thank you. You are right. It would be better to write the definition of pd_keyfunc as:

    Code:
    def pd_keyfunc(item):
        return item.path + item.date.strftime("%Y-%m-%d, %H:%M:%S")
    The folders should then be in time order to the second.

Page 4 of 4 FirstFirst ... 234

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •