Update metadata for file from separate BibTeX file

I’ve recently started using DEVONthink PRO to manage my library of PDFs. Unfortunately, given my current setup, I’m not able to make most of DEVONthink to browse through my library. I’m hoping someone here might be able to help.

My library of PDFs contains a number of files all of which are titled using the corresponding citation key in my main .bib database. Thus, for each PDF in my library titled key.pdf, there’s an entry in my main .bib file with all the necessary metadata (title, author, publication year, etc.).

I’d like to find a way of using the metadata to browse through the library of PDFs using DEVONthink. I can imagine, though I’m not yet in a position to implement, a number of sophisticated position. But perhaps it would be enough to do something like this: For each item in the library, use its title (of the form key.pdf to fetch information from my main .bib file that would then be used to define an alias for the pdf. I would then be able to have a view of my library in DEVONthink that would contain author and title information for each entry.

Does anyone have any hints on how best to go about doing this? Has anyone dealt with a similar situation?

I realize I could just rename files using the metadata, perhaps relying on something like Zotero or BibDesk, but that would not work for me. The main constraint is to have each PDF associated with an entry in my main .bib file named using the format key.pdf where key is, of course, the key corresponding to said entry.

Thanks in advance for any help you can provide.

Welcome @pzrcrbll

Unfortunately, given my current setup, I’m not able to make most of DEVONthink to browse through my library

What inhibits this activity?

Thanks for your quick reply. The main issue is that the file name does not contain enough information to e.g. order by author or title etc. I realize one could use metadata embedded in the PDF, when available, for browsing. And in a way, that would be ideal—the file name is the last thing I want to know about a PDF in this context. Trouble is, many of the PDFs I have in my library do not have adequate metadata. If I could use my .bib file to populate the metadata of the PDF that would be wonderful, but I do not know how to do that either.

How about using an applescript to access that metadata and copy it to the Devonthink record

I thought about that, but I know almost nothing about scripting with AppleScript. I’ll take a look and see if I can put something together. Do you off the top of your head know of a good reference where I could learn more about writing to the DT record using applescript? Thanks!

Open your BibTeX file in Bibdesk (a free, open-source bib manager). This script will take the selection in Bibdesk, look for the corresponding PDF file in DEVONthink 3, and sync the metadata. Keep in mind that It will sync only the selected entries in Bibdesk. The DEVONthink database with the PDF file must be open.


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

-- Script to link Bibdesk entries to DEVONthink Pro records along with custom metadata - by Bernardo Vasconcelos (2022).
-- Use at your own risk

tell application "BibDesk"
	
	
	set theSelection to the selection of document 1
	repeat with thisItem in theSelection
		-- accessing field values
		set theID to id of thisItem
		set theCitation to cite key of thisItem
		--set thePriority to the rating of thisItem as text
		set theType to the type of thisItem as text
		set theRating to the value of field "rating" of thisItem as text
		
		set theTitle to the value of field "Title" of thisItem
		set theAuthor to the name of author of field "Author" of item 1 of theSelection as text
		set theAbstract to the value of field "abstract" of thisItem
		set theEditor to the value of field "editor" of thisItem
		set theTranslator to the value of field "Translator" of thisItem
		
		set thePlace to the value of field "Address" of thisItem
		set thePublisher to the value of field "publisher" of thisItem
		set theYear to the value of field "Year" of thisItem
		set theISBN to the value of field "isbn" of thisItem
		
		set theJournal to the value of field "journal" of thisItem
		set theVolume to the value of field "volume" of thisItem
		set theIssue to the value of field "volume" of thisItem
		set thePages to the value of field "pages" of thisItem
		set theDOI to the value of field "doi" of thisItem
		
		set theNotes to the value of field "Annote" of thisItem
		set theKeywords to the value of field "keywords" of thisItem
		set theLanguage to the value of field "language" of thisItem
		set theAttachments to the value of field "attachments" of thisItem
		set theURL to the linked URL of thisItem
		
		try
			set refVolume to ""
			if theVolume is not "" then
				set refVolume to " (" & the_volume & ")"
			end if
		end try
		try
			set refTranslator to ""
			if theTranslator is not "" then
				set refTranslator to "Trad.: " & theTranslator & ". "
			end if
		end try
		try
			set refEditor to ""
			if theEditor is not "" then
				set refEditor to "Ed.: " & theEditor & ". "
			end if
		end try
		try
			set refArticle to ""
			set refArticle to (theAuthor & ". " & theTitle & ". In: " & theJournal & " " & refVolume & theIssue & ", " & theYear & "." & " Pp." & thePages)
		end try
		try
			set refBook to ""
			set refBook to (theAuthor & "; " & theTitle & ". " & refEditor & refTranslator & thePlace & ": " & thePublisher & ", " & theYear)
		end try
		
		try
			set theRef to ""
			if (theType = "article") then
				set theRef to refArticle
			else if (theType = "book") then
				set theRef to refBook
			end if
		end try
		
	end repeat
	
	
	tell application id "DNtp"
		
		set thePDF to search "filename:" & theCitation & ".pdf"
		
		try
			set theRecord to the content record of think window 1
			if theRecord is {} then error "Please select some contents."
		end try
		
		try
			set thePriority to ""
			if theRating is "1" then set thePriority to "1️⃣"
			if theRating is "2" then set thePriority to "2️⃣"
			if theRating is "3" then set thePriority to "🔥"
			if theRating is "4" then set thePriority to "🔥🔥"
			if theRating is "5" then set thePriority to "🔥🔥🔥"
		end try
		
		
		try
			
			add custom meta data theCitation for "bibkey" to theRecord
			
			add custom meta data thePriority for "Priority" to theRecord
			add custom meta data theRating for "rating" to theRecord
			add custom meta data theType for "type" to theRecord
			add custom meta data theTitle for "title" to theRecord
			add custom meta data theAbstract for "abstract" to theRecord
			
			add custom meta data theAuthor for "authors" to theRecord
			add custom meta data theEditor for "editor" to theRecord
			add custom meta data theTranslator for "translator" to theRecord
			
			add custom meta data thePlace for "Place" to theRecord
			add custom meta data thePublisher for "publisher" to theRecord
			add custom meta data theYear for "date" to theRecord
			add custom meta data theISBN for "is?n" to theRecord
			
			add custom meta data theJournal for "journal" to theRecord
			add custom meta data theVolume for "volume" to theRecord
			add custom meta data theIssue for "issue" to theRecord
			add custom meta data thePages for "page" to theRecord
			add custom meta data theDOI for "doi" to theRecord
			
			add custom meta data theRef for "Reference" to theRecord
			
			add custom meta data theNotes for "notas" to theRecord
			add custom meta data theKeywords for "keywords" to theRecord
			add custom meta data theLanguage for "language" to theRecord
			add custom meta data ("x-bdsk://" & theCitation) for "bibdeskurl" to theRecord
			add custom meta data theURL for "link2" to theRecord
			
			--set the URL of theRecord to ("x-bdsk://" & theCitation) as text
		end try
		try
			set the aliases of theRecord to theCitation
			set the tags of theRecord to theKeywords
			set the name of theRecord to theRef
			
			set theDntp_Link to ""
			set theDntp_Link to reference URL of theRecord
		end try
	end tell
end tell


tell application "BibDesk"
	set theSelection to the selection of document 1
	set the value of field "Local-url" of thisItem to theDntp_Link
end tell



5 Likes

I forgot to say: test it on dummy files first. And keep backups.

You cannot undo changes made by scripts. That is, ⌘Z won’t work after running the script.

My suggestion is: try with a dummy BibTeX file and dummy PDF files. Just name them as you would name your real files. Then make adjustments to the script to better fit your needs. On the first try, whatever you do, don’t just select your whole library and run it blindly.

3 Likes

Thanks, @Bernardo_V for your suggestion. I haven’t tried this yet but will report back!

In addition to Bibdesk as described above by @Bernardo_V, you could accomplish all of what you described using a combination of Zotero, some Zotero extensions, and additional software and workflows, but getting there will take some time and perseverance. Unlike for Bookends, DEVONthink doesn’t have anything out of the box to support Zotero, but the following may help get a sense of how it could be done:

  • Renaming your PDFs based on BibTeX citekeys could be achieved in Zotero using a combination of the extensions Better BibTeX and Zotfile. The former generates BibTeX citekeys; the latter can rename/move/reorganize files based on a configuration you define.
  • In DEVONthink, you can index the folder of PDFs maintained by Zotero, and thus gain ability to search, annotate and mark up the PDFs in DEVONthink, and more.
  • It is possible to set things up so that the URL field for a PDF in DEVONthink is the Zotero entry, which makes it convenient and quick to jump from DEVONthink to Zotero where you keep full bibliographic information. The DEVONthink keyboard shortcut is u (“Launch URL”). To make this possible, you have to use a combination of smart rules in DEVONthink and some external software that will communicate with Zotero to get the information. Some postings that describe people’s approaches are this one and this one and also this thread.

Some other users here have posted some more info about Zotfile to reorganize the Zotero PDFs in other ways; see, e.g., Automate Indexing of a Zotero *Collection*? - #10 by rpallred.

It is also possible to store more bibliographic data directly in DEVONthink by defining custom metadata fields. Then, every document (including every external PDF indexed by DEVONthink) can have values for those custom metadata fields. I myself have a setup by which I store BibTeX citekeys, year, and type of reference (journal, book, etc.) in custom fields. Getting those values out of Zotero and into the metadata fields is done using DEVONthink smart rules that run another external tool I’ve been working on. (It’s unfortunately not in a state where other people could easily use, but I hope to get it out there someday soon …) Anyway, my point is that by defining custom fields in DEVONthink to store the data you want, you could achieve better bibliographic handling and integration with other tools – something worth keeping in mind no matter what you use, Zotero or otherwise.

2 Likes

It is also possible to store more bibliographic data directly in DEVONthink by defining custom metadata fields.

Indeed this is true… if you’re running the Pro or Server edition. :slight_smile:

Thanks everyone for your suggestions. I do have the Pro version, so that’s a solution to look into. For now, I came up with a somewhat crude bit of Emacs lisp that does what I need, by passing the metadata to exiftool and writing author and title information on the PDF. If anyone is interested, I’d be happy to share…

Feel free to share your methods. We do have some other emacs users in here :slight_smile:

OK, for what it’s worth, what I’m doing for now is now up on the Wiki page of Emacs’s citar package—my solution builds on that packages functions, so it only made sense to make it available up there as well.

Here at any rate is the function I’m using:

(defvar ex/citar-library-backup-path "/path/to/library/backup")

(defun ex/update-pdf-metadata-alt (key-entry)
  "Add/update metadata of PDF for KEY-ENTRY."
(interactive (list (citar-select-ref)))
  (let* ((entry (cdr key-entry))
         (key (car key-entry))
         (file (car (citar-file--files-for-entry
                     key
                     entry
                     citar-library-paths
                     '("pdf"))))
         (nofile nil)
         (title (citar-clean-string (citar-get-value 'title entry)))
         (author (cond ((citar-has-a-value '(author) entry)
                        (citar-get-value 'author entry))
                        ((citar-has-a-value '(editor) entry)
                         (concat (citar-get-value 'editor entry) " (ed.)")))))
    (if (not file)
        (print (format "I could not find an PDF file associated with \'%s\'" key))
      (progn
        (copy-file file my/bib-library-backup-path 1)
        (call-process-shell-command
         (concat "exiftool -overwrite_original_in_place -Title='" title "' -Author='" author "' " file))))))
1 Like

@Bernardo_V, this looks very helpful. I was getting an error at first. It wasn’t working when I ran it on a record that was indexed in DT3, but then I resolved the issue by importing the PDF into DEVONthink. It seemed like this script only worked if the PDF has been imported, but then I tried testing it with different PDFs, and I was surprised to discover that it successfully updated the metadata for an indexed file!

I experimented running the script on a handful of different records, but I couldn’t figure out what conditions must be met for it to run successfully. It seems like if I select the records that I want to sync in both DT3 and BibDesk, then it always does what it’s supposed to. But besides that, I can’t figure it out.

I want to modify the script so that if the BibDesk record contains a valid path in the “file” field, DEVONthink will index that path (or find the file if already indexed) and then sync the metadata from BibDesk to the DT3 item. But I’m stumped.

@aaaaaaaaaaaaaaaa, you can use lookup record with path to find a record using a file path. Take a look at the Applescript dictionary or search the forum for this command to find examples. If you remain stumped after trying this, just let us know.

3 Likes