adamreeve / Mendeley-FileSync

A script to synchronise PDF files in Mendeley across multiple machines
GNU General Public License v3.0
24 stars 4 forks source link

Feature Request -- script to launch Mendeley #9

Open jfburkhart opened 10 years ago

jfburkhart commented 10 years ago

Not really an issue, but rather working on a different approach. Maybe you could help make this more robust / generic.

I'm trying to create a python script that opens the database before and after launching mendeley and modifies it to fit whichever system your are running. I have it working now that it will change the Organiser/OrganiserLocation, but now I need to deal with the Files table and the localUrl problems... and it would certainly make sense to use what you've created.

Here's what I have so far:

#!/usr/bin/env python
import sqlite3 as lite
import subprocess
import shutil
import os
from glob import glob

if os.name == 'posix':
    HOME = os.environ['HOME']
    data_dir = os.path.join(HOME, r'.local/share/data/Mendeley Ltd./Mendeley Desktop')
    organiser_location = os.path.join(HOME, r'/Dropbox/Library')
elif os.name == 'nt':
    HOME = os.environ['HOME']
    APPDIR = os.environ['LOCALAPPDATA']
    data_dir = os.path.join(APPDIR, '/Mendeley Ltd/Mendeley Desktop')
    organiser_location = os.path.join(HOME, r'/Dropbox/Library'
else:
    raise IOError('Cannot Locate Database')

local_data = (r'Organiser/OrganiserLocation', organiser_location)       

MENDELEY_DB = glob(os.path.join(data_dir, '*www.mendeley.com.sqlite'))[0]
print MENDELEY_DB
print data_dir
MENDELEY_DB_BAK=os.path.join(MENDELEY_DB + '.bak')

class MendeleyDB(object):
    """
    An interface to the Mendeley database
    """

    def __init__(self, path, dry_run=False):
        self.path = path
        self.dry_run = dry_run
        self.__enter__()

    def __enter__(self):
        """
        Open the database connection
        """

        self.connection = lite.connect(self.path)
        self.cursor = self.connection.cursor()
        return self

    def exit(self):
        """
        Close the database connection
        """

        self.connection.commit()
        self.cursor.close()

    def execute_unsafe(self, statement):
        """
        Execute an SQL statement that may alter data

        If dry_run is set, print the statement and don't execute anything.
        This is useful for debugging or just for peace of mind.
        """

        if self.dry_run:
            s = statement
            print("Executing: %s" % s)
        else:
            return self.cursor.execute(statement)

## Make a backup of the database
shutil.copy(MENDELEY_DB, MENDELEY_DB_BAK)

## open the database to make changes
mdb = MendeleyDB(MENDELEY_DB)

## Print current settings
statement = r'SELECT * FROM Settings WHERE key="Organiser/OrganiserLocation"'
original_data = mdb.execute_unsafe(statement)
original_data = mdb.cursor.fetchone()

## Change settings to local Organiser
statement = r'UPDATE Settings SET value="{1}" WHERE key="{0}"'.format(*local_data)
data = mdb.execute_unsafe(statement)

mdb.exit()

## Now run mendeley and wait for exit.
command='mendeleydesktop'
subprocess.call([command, ''])

## When mendeley exits, change back to orginal settings
## open the database to make changes
mdb = MendeleyDB(MENDELEY_DB)

## Change settings back
statement = r'UPDATE Settings SET value="{1}" WHERE key="{0}"'.format(*original_data)
data = mdb.execute_unsafe(statement)

mdb.exit()
adamreeve commented 10 years ago

Hi, that sounds like a good approach and would be a lot less annoying than having to use the synchronisation script. Are you planning on synchronising the database file with Dropbox too and then copying it to where Mendeley expects it to be? I think you could use MendeleyDB.document_files to find all the documents with a localUrl that need updating and then use MendeleyDB.update_file to update the url with a new base path. You'll have to reorganise how the base_url attribute is used though so that in MendeleyDB.get_file_name it would know how to strip off the original base path from the file url. That might be a bit tricky.

jfburkhart commented 10 years ago

I forked your version, and have created something the 'delicately' works, but it is far from robust. Have a look, I've used now your classes from the mendeleyfilesync.MendeleyDB module class, but I had to add a few methods and make one change, and I don't know what impact that would have elsewhere: https://github.com/jfburkhart/Mendeley-FileSync/commit/b615227ab931f53b62d44cbd5a6403ece98bc7d0 See this commit and the messages at the bottom regarding your setting of: path = os.path.abspath(path)

jfburkhart commented 10 years ago

What I have set up now is that my Organizer Library is stored on Dropbox, both systems see it. My config directory for Mendeley is also stored in the cloud (Copy actually) and I've created symlinks on both the linux system and on the windows side (I forget what symlinks are called in window, but the point is that %LOCALAPPDATA%//Mendeley Ltd/Mendeley Desktop/ actually points to my Copy cloud storage.

In Windows I don't modify anything, but on linux when I start up, I modify the database and switch the monitor.sql database, then when the program closes, I revert everything.

Note that in Linux, I've actually replaced /usr/bin/mendeleydesktop to point to my python script and have a binary called mendeleydesktop.bin that the python script calls.

I wouldn't call it elegant or robust, but it seems to be working! ;)

adamreeve commented 10 years ago

Ok cool, I'm not sure why you would have needed to remove the path = os.path.abspath(path) line, that converts a relative path to an absolute path and shouldn't have any effect if the path is already absolute. It isn't obvious how that could have affected your code unless the way Mendeley stores the OrganiserLocation path is a bit weird.

mherrmann3 commented 8 years ago

Hey Adam, it's now been 2 years since the last discussion about your script and I was wondering if you still use it yourself - or if you have found a better solution / a better software? Mendeley's feature integration seems to be REALLY cumbersome, especially for features that have a high voting on feedback.mendeley.com (The relative paths issue is at 8th place!).

Let me know!

(Btw: I ported your script to python3 in the meantime - was not much to do :-))

adamreeve commented 8 years ago

Hi, no I don't use this script myself any more, and I don't use Mendeley or any other reference management software because I'm not working in academia. I'm not aware of anything better, and it's a bit disappointing to see this is still an issue in Mendeley. I'll keep accepting bug fixes here if people are still finding this script useful but won't be planning on making any changes to the script myself.

mherrmann3 commented 8 years ago

Ok, thanks Adam for letting me know. I'll continue to use Mendeley in combination with your script. I'm convinced that it's still the best way to go for now. Cheers