diff --git a/README.md b/README.md index f3025939..4b9eca25 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,36 @@ -# Sisyphos DBX +# BirdBox Open-source Dropbox command line client for macOS and Linux. ## About -Sisyphos DBX is an open-source Dropbox client written in Python. The project's main goal is to provide an open-source desktop Dropbox client for platforms that aren't supported. SisyphosDBX is script-based which makes it platform-independent. It's written using the Python SDK for Dropbox API v2. +BirdBox is an open-source Dropbox client written in Python. The project's main goal is to provide an open-source desktop Dropbox client for platforms that aren't supported. It's written using the Python SDK for Dropbox API v2. -Sisyphos DBX remembers its last settings and resumes syncing after a restart. You can also pause and resume syncing while SisyphosDBX is running, add and remove exluded folders, and change the Dropbox location on the local drive. +BirdBox remembers its last settings and resumes syncing after a restart. You can also pause and resume syncing while BirdBox is running, add and remove exluded folders, and change the Dropbox location on the local drive. ## Interactive usage (Python shell) After installation, in a Python command prompt, run ```Python ->>> from sisyphosdbx import SisyphosDBX ->>> sdbx = SisyphosDBX() +>>> from birdbox import BirdBox +>>> bb = BirdBox() ``` -On initial use, SisyphosDBX will ask you to link your dropbox account, give the location of your Dropbox folder on the local drive, and to specify excluded folders. It will then start syncing. Supported commands are: +On initial use, BirdBox will ask you to link your dropbox account, give the location of your Dropbox folder on the local drive, and to specify excluded folders. It will then start syncing. Supported commands are: ```Python ->>> sdbx.pause_sync() # pause syncing ->>> sdbx.resume_sync() # resume syncing +>>> bb.pause_sync() # pause syncing +>>> bb.resume_sync() # resume syncing >>> path = '/Folder/On/Dropbox' # path relative to Dropbox folder ->>> sdbx.exclude_folder(path) # exclude Dropbox folder from sync, delete locally ->>> sdbx.include_folder(path) # inlcude Dropbox folder in sync, download its contents +>>> bb.exclude_folder(path) # exclude Dropbox folder from sync, delete locally +>>> bb.include_folder(path) # inlcude Dropbox folder in sync, download its contents ->>> sdbx.set_dropbox_directory('~/Dropbox') # give path for local dropbox folder ->>> sdbx.unlink() # unlinks your Dropbox account but keeps are your files +>>> bb.set_dropbox_directory('~/Dropbox') # give path for local dropbox folder +>>> bb.unlink() # unlinks your Dropbox account but keeps are your files ``` You can get information about your Dropbox account and direct access uploading, downloading and moving files / folders on your Dropbox through the SisyphosDBX API client. Some example commands include: ```Python ->>> from sisyphosdbx.client import SisyphosClient +>>> from birdbox.client import BirdBoxClient >>> client = SisyphosClient() >>> client.upload(local_path, dropbox_path) # uploads file form local_path to Dropbox @@ -45,16 +45,16 @@ You can get information about your Dropbox account and direct access uploading, ``` ## Command line usage -After installation, Sisyphos DBX will be available as a command line script by typing `sisyphosdbx` in the command prompt. Command line functionality resembles that of the interactive client. Type `sisyphosdbx --help` to get a full list of available commmands. Invoking `sisyphosdbx` by itself will configure Sisyphos DBX on first run and then automatically start syncing. +After installation, BirdBox will be available as a command line script by typing `birdbox` in the command prompt. Command line functionality resembles that of the interactive client. Type `birdbox --help` to get a full list of available commmands. Invoking `birdbox` by itself will configure BirdBox on first run and then automatically start syncing. ## Warning: -- SisyphosDBX doesn't have production status yet, so only 500 accounts can use the API keys. -- SisyphosDBX is still in beta status and may potentially result in loss of data. Only sync folders with non-essential files. +- BirdBox doesn't have production status yet, so only 500 accounts can use the API keys. +- BirdBox is still in beta status and may potentially result in loss of data. Only sync folders with non-essential files. ## Installation Download and install the package by running ```console -$ pip git+https://github.com/SamSchott/sisyphosdbx +$ pip git+https://github.com/SamSchott/birdbox ``` in the command line. diff --git a/sisyphosdbx/__init__.py b/birdbox/__init__.py similarity index 100% rename from sisyphosdbx/__init__.py rename to birdbox/__init__.py diff --git a/sisyphosdbx/bin/__init__.py b/birdbox/bin/__init__.py similarity index 100% rename from sisyphosdbx/bin/__init__.py rename to birdbox/bin/__init__.py diff --git a/sisyphosdbx/bin/command_line.py b/birdbox/bin/command_line.py similarity index 100% rename from sisyphosdbx/bin/command_line.py rename to birdbox/bin/command_line.py diff --git a/sisyphosdbx/client.py b/birdbox/client.py similarity index 100% rename from sisyphosdbx/client.py rename to birdbox/client.py diff --git a/sisyphosdbx/config/__init__.py b/birdbox/config/__init__.py similarity index 100% rename from sisyphosdbx/config/__init__.py rename to birdbox/config/__init__.py diff --git a/sisyphosdbx/config/base.py b/birdbox/config/base.py similarity index 100% rename from sisyphosdbx/config/base.py rename to birdbox/config/base.py diff --git a/sisyphosdbx/config/main.py b/birdbox/config/main.py similarity index 100% rename from sisyphosdbx/config/main.py rename to birdbox/config/main.py diff --git a/sisyphosdbx/config/user.py b/birdbox/config/user.py similarity index 100% rename from sisyphosdbx/config/user.py rename to birdbox/config/user.py diff --git a/sisyphosdbx/gui/__init__.py b/birdbox/gui/__init__.py similarity index 100% rename from sisyphosdbx/gui/__init__.py rename to birdbox/gui/__init__.py diff --git a/sisyphosdbx/gui/error_dialog.ui b/birdbox/gui/error_dialog.ui similarity index 100% rename from sisyphosdbx/gui/error_dialog.ui rename to birdbox/gui/error_dialog.ui diff --git a/sisyphosdbx/gui/first_sync_dialog.py b/birdbox/gui/first_sync_dialog.py similarity index 99% rename from sisyphosdbx/gui/first_sync_dialog.py rename to birdbox/gui/first_sync_dialog.py index c7165767..97e76c4b 100644 --- a/sisyphosdbx/gui/first_sync_dialog.py +++ b/birdbox/gui/first_sync_dialog.py @@ -243,7 +243,7 @@ class FirstSyncDialog(QtWidgets.QWidget): # static method to create the dialog and return BirdBox instance on success @staticmethod - def runUserSetup(parent=None): + def configureBirdBox(parent=None): dialog = FirstSyncDialog(parent) dialog.exec_() return dialog.bb diff --git a/sisyphosdbx/gui/first_sync_dialog.ui b/birdbox/gui/first_sync_dialog.ui similarity index 100% rename from sisyphosdbx/gui/first_sync_dialog.ui rename to birdbox/gui/first_sync_dialog.ui diff --git a/sisyphosdbx/gui/folders_dialog.py b/birdbox/gui/folders_dialog.py similarity index 100% rename from sisyphosdbx/gui/folders_dialog.py rename to birdbox/gui/folders_dialog.py diff --git a/sisyphosdbx/gui/folders_dialog.ui b/birdbox/gui/folders_dialog.ui similarity index 100% rename from sisyphosdbx/gui/folders_dialog.ui rename to birdbox/gui/folders_dialog.ui diff --git a/sisyphosdbx/gui/main.py b/birdbox/gui/main.py similarity index 89% rename from sisyphosdbx/gui/main.py rename to birdbox/gui/main.py index cd83fb79..e4fcf711 100644 --- a/sisyphosdbx/gui/main.py +++ b/birdbox/gui/main.py @@ -10,6 +10,7 @@ from PyQt5 import QtCore, QtWidgets, QtGui from birdbox.main import BirdBox from birdbox.gui.settings import SettingsWindow +from bridbox.gui.first_sync_dialog import FirstSyncDialog from birdbox.config.main import CONF _root = QtCore.QFileInfo(__file__).absolutePath() @@ -103,9 +104,13 @@ for logger_name in ["birdbox.monitor", "birdbox.main", "birdbox.client"]: class BirdBoxApp(QtWidgets.QSystemTrayIcon): DARK = os.popen("defaults read -g AppleInterfaceStyle").read() == "Dark" + FIRST_SYNC = (not CONF.get("internal", "lastsync") or + CONF.get("internal", "cursor") == "" or + not os.path.isdir(CONF.get("main", "path"))) def __init__(self, parent=None): - # load menu bar icons + # Load menu bar icons as instance attributes and not as class + # attributes since QApplication may not be running. self.icon_idle = QtGui.QIcon(_root + "/resources/menubar_icon_idle.svg") self.icon_syncing = QtGui.QIcon(_root + "/resources/menubar_icon_syncing.svg") self.icon_paused = QtGui.QIcon(_root + "/resources/menubar_icon_paused.svg") @@ -116,17 +121,30 @@ class BirdBoxApp(QtWidgets.QSystemTrayIcon): self.icon_disconnected.setIsMask(True) self.icon_paused.setIsMask(True) - # initialize tray widget + # initialize system tray widget QtWidgets.QSystemTrayIcon.__init__(self, self.icon_disconnected, parent) # start BirdBox - self.bb = BirdBox(run=False) + if self.FIRST_SYNC: # run configuration wizard on first startup + self.bb = FirstSyncDialog.configureBirdBox(self) + self.bb.download_complete_signal.connect(self.bb.start_sync) + if self.bb is None: + self.deleteLater() + QtCore.QCoreApplication.quit() + else: + self.setup_ui() + + else: # start BirdBox normally otherwise + self.bb = BirdBox() + self.setup_ui() + + def setup_ui(self): # create settings window self.settings = SettingsWindow(self.bb, parent=None) # create context menu - self.menu = QtWidgets.QMenu(parent) + self.menu = QtWidgets.QMenu(self) self.openFolderAction = self.menu.addAction("Open Dropbox Folder") self.openWebsiteAction = self.menu.addAction("Launch Dropbox Website") self.separator1 = self.menu.addSeparator() diff --git a/sisyphosdbx/gui/resources/Accounts.icns b/birdbox/gui/resources/Accounts.icns similarity index 100% rename from sisyphosdbx/gui/resources/Accounts.icns rename to birdbox/gui/resources/Accounts.icns diff --git a/sisyphosdbx/gui/resources/General.icns b/birdbox/gui/resources/General.icns similarity index 100% rename from sisyphosdbx/gui/resources/General.icns rename to birdbox/gui/resources/General.icns diff --git a/sisyphosdbx/gui/resources/GenericFolderIcon.icns b/birdbox/gui/resources/GenericFolderIcon.icns similarity index 100% rename from sisyphosdbx/gui/resources/GenericFolderIcon.icns rename to birdbox/gui/resources/GenericFolderIcon.icns diff --git a/sisyphosdbx/gui/resources/GenericFolderIcon.png b/birdbox/gui/resources/GenericFolderIcon.png similarity index 100% rename from sisyphosdbx/gui/resources/GenericFolderIcon.png rename to birdbox/gui/resources/GenericFolderIcon.png diff --git a/sisyphosdbx/gui/resources/GenericNetworkIcon.icns b/birdbox/gui/resources/GenericNetworkIcon.icns similarity index 100% rename from sisyphosdbx/gui/resources/GenericNetworkIcon.icns rename to birdbox/gui/resources/GenericNetworkIcon.icns diff --git a/sisyphosdbx/gui/resources/HomeFolderIcon.icns b/birdbox/gui/resources/HomeFolderIcon.icns similarity index 100% rename from sisyphosdbx/gui/resources/HomeFolderIcon.icns rename to birdbox/gui/resources/HomeFolderIcon.icns diff --git a/sisyphosdbx/gui/resources/HomeFolderIcon.png b/birdbox/gui/resources/HomeFolderIcon.png similarity index 100% rename from sisyphosdbx/gui/resources/HomeFolderIcon.png rename to birdbox/gui/resources/HomeFolderIcon.png diff --git a/sisyphosdbx/gui/resources/Notifications.icns b/birdbox/gui/resources/Notifications.icns similarity index 100% rename from sisyphosdbx/gui/resources/Notifications.icns rename to birdbox/gui/resources/Notifications.icns diff --git a/sisyphosdbx/gui/resources/UserIcon.icns b/birdbox/gui/resources/UserIcon.icns similarity index 100% rename from sisyphosdbx/gui/resources/UserIcon.icns rename to birdbox/gui/resources/UserIcon.icns diff --git a/sisyphosdbx/gui/resources/app_icon.key b/birdbox/gui/resources/app_icon.key similarity index 100% rename from sisyphosdbx/gui/resources/app_icon.key rename to birdbox/gui/resources/app_icon.key diff --git a/sisyphosdbx/gui/resources/app_icon.svg b/birdbox/gui/resources/app_icon.svg similarity index 100% rename from sisyphosdbx/gui/resources/app_icon.svg rename to birdbox/gui/resources/app_icon.svg diff --git a/sisyphosdbx/gui/resources/folder_dialog_resources.qrc b/birdbox/gui/resources/folder_dialog_resources.qrc similarity index 100% rename from sisyphosdbx/gui/resources/folder_dialog_resources.qrc rename to birdbox/gui/resources/folder_dialog_resources.qrc diff --git a/sisyphosdbx/gui/resources/menubar_icon_disconnected.svg b/birdbox/gui/resources/menubar_icon_disconnected.svg similarity index 100% rename from sisyphosdbx/gui/resources/menubar_icon_disconnected.svg rename to birdbox/gui/resources/menubar_icon_disconnected.svg diff --git a/sisyphosdbx/gui/resources/menubar_icon_idle.svg b/birdbox/gui/resources/menubar_icon_idle.svg similarity index 100% rename from sisyphosdbx/gui/resources/menubar_icon_idle.svg rename to birdbox/gui/resources/menubar_icon_idle.svg diff --git a/sisyphosdbx/gui/resources/menubar_icon_paused.svg b/birdbox/gui/resources/menubar_icon_paused.svg similarity index 100% rename from sisyphosdbx/gui/resources/menubar_icon_paused.svg rename to birdbox/gui/resources/menubar_icon_paused.svg diff --git a/sisyphosdbx/gui/resources/menubar_icon_syncing.svg b/birdbox/gui/resources/menubar_icon_syncing.svg similarity index 100% rename from sisyphosdbx/gui/resources/menubar_icon_syncing.svg rename to birdbox/gui/resources/menubar_icon_syncing.svg diff --git a/sisyphosdbx/gui/resources/settings_resources.qrc b/birdbox/gui/resources/settings_resources.qrc similarity index 100% rename from sisyphosdbx/gui/resources/settings_resources.qrc rename to birdbox/gui/resources/settings_resources.qrc diff --git a/sisyphosdbx/gui/resources/start_dialog_resources.qrc b/birdbox/gui/resources/start_dialog_resources.qrc similarity index 100% rename from sisyphosdbx/gui/resources/start_dialog_resources.qrc rename to birdbox/gui/resources/start_dialog_resources.qrc diff --git a/sisyphosdbx/gui/resources/sync.icns b/birdbox/gui/resources/sync.icns similarity index 100% rename from sisyphosdbx/gui/resources/sync.icns rename to birdbox/gui/resources/sync.icns diff --git a/sisyphosdbx/gui/resources/unlink_dialog_resources.qrc b/birdbox/gui/resources/unlink_dialog_resources.qrc similarity index 100% rename from sisyphosdbx/gui/resources/unlink_dialog_resources.qrc rename to birdbox/gui/resources/unlink_dialog_resources.qrc diff --git a/sisyphosdbx/gui/settings.py b/birdbox/gui/settings.py similarity index 100% rename from sisyphosdbx/gui/settings.py rename to birdbox/gui/settings.py diff --git a/sisyphosdbx/gui/settings.ui b/birdbox/gui/settings.ui similarity index 100% rename from sisyphosdbx/gui/settings.ui rename to birdbox/gui/settings.ui diff --git a/sisyphosdbx/gui/unlink_dialog.ui b/birdbox/gui/unlink_dialog.ui similarity index 100% rename from sisyphosdbx/gui/unlink_dialog.ui rename to birdbox/gui/unlink_dialog.ui diff --git a/sisyphosdbx/main.py b/birdbox/main.py similarity index 97% rename from sisyphosdbx/main.py rename to birdbox/main.py index ddfd9217..69b1ef44 100644 --- a/sisyphosdbx/main.py +++ b/birdbox/main.py @@ -6,7 +6,7 @@ __author__ = "Sam Schott" import os import os.path as osp import time -# import requests +import requests import shutil import functools from blinker import signal @@ -14,7 +14,7 @@ from threading import Thread from dropbox import files from birdbox.client import BirdBoxClient -from birdbox.monitor import BirdBoxMonitor +from birdbox.monitor import BirdBoxMonitor, CONNECTION_ERRORS from birdbox.config.main import CONF import logging @@ -46,7 +46,7 @@ def folder_download_worker(client, dbx_path, lock): logger.info("Up to date") except (KeyboardInterrupt, SystemExit): raise - except Exception as e: # requests.exceptions.RequestException + except CONNECTION_ERRORS as e: logger.debug("{0}: {1}".format(ERROR_MSG, e)) download_complete_signal.send() @@ -87,7 +87,7 @@ def if_connected(f): return res except (KeyboardInterrupt, SystemExit): raise - except Exception as e: # requests.exceptions.RequestException + except CONNECTION_ERRORS as e: logger.debug("{0}: {1}".format(ERROR_MSG, e)) return False @@ -165,7 +165,7 @@ class BirdBox(object): args=(self.client, dbx_path, self.monitor.lock), name="BirdBoxFolderDownloader") self.download_thread.start() - self.download_complete_signal.connect(self.resume_sync) + self.download_complete_signal.connect(self.monitor.resume) def start_sync(self, overload=None): """ diff --git a/sisyphosdbx/monitor.py b/birdbox/monitor.py similarity index 98% rename from sisyphosdbx/monitor.py rename to birdbox/monitor.py index 9c6cfd50..0ac90254 100644 --- a/sisyphosdbx/monitor.py +++ b/birdbox/monitor.py @@ -4,11 +4,10 @@ import logging import time from threading import Thread, Event, Lock from concurrent.futures import ThreadPoolExecutor -# import requests +import requests import queue from blinker import signal import dropbox - from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler from watchdog.events import (EVENT_TYPE_CREATED, EVENT_TYPE_DELETED, @@ -18,14 +17,18 @@ from watchdog.events import (DirModifiedEvent, FileModifiedEvent, DirDeletedEvent, FileDeletedEvent) from watchdog.utils.dirsnapshot import DirectorySnapshot -from birdbox.config.main import CONF, SUBFOLDER -from birdbox.config.base import get_conf_path - -configurationDirectory = get_conf_path(SUBFOLDER) +from birdbox.config.main import CONF logger = logging.getLogger(__name__) +CONNECTION_ERRORS = ( + requests.exceptions.Timeout, + requests.exceptions.ConnectionError, + requests.exceptions.HTTPError + ) + + class TimedQueue(queue.Queue): """ A queue that remembers the time of the last put. @@ -255,7 +258,7 @@ def connection_helper(client, connected, running): time.sleep(5) except (KeyboardInterrupt, SystemExit): raise - except Exception as e: # requests.exceptions.RequestException + except CONNECTION_ERRORS as e: logger.debug(e) running.clear() connected.clear() @@ -300,7 +303,7 @@ def remote_worker(client, running, fh_running, lock): logger.info("Up to date") except (KeyboardInterrupt, SystemExit): raise - except Exception as e: # requests.exceptions.RequestException + except CONNECTION_ERRORS as e: logger.debug(e) logger.info("Connecting...") disconnected_signal.send() @@ -423,7 +426,7 @@ def upload_worker(dbx_uploader, local_q, running, lock): logger.info("Up to date") except (KeyboardInterrupt, SystemExit): raise - except Exception as e: # requests.exceptions.RequestException + except CONNECTION_ERRORS as e: logger.debug(e) logger.info("Connecting...") disconnected_signal.send() diff --git a/sisyphosdbx/notify/__init__.py b/birdbox/notify/__init__.py similarity index 100% rename from sisyphosdbx/notify/__init__.py rename to birdbox/notify/__init__.py diff --git a/sisyphosdbx/notify/main.py b/birdbox/notify/main.py similarity index 100% rename from sisyphosdbx/notify/main.py rename to birdbox/notify/main.py