1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2025-05-09 18:29:49 +00:00

Compare commits

..

No commits in common. "5a4958cff9f808c3ae2b3f5514d6e03be66a0002" and "06eca11f0b985bd7c80fe89d41cf8337595888c7" have entirely different histories.

13 changed files with 107 additions and 113 deletions

27
.travis.yml Normal file
View File

@ -0,0 +1,27 @@
sudo: false
language: python
install:
- pip3 install -r requirements.txt -r requirements-extra.txt
script: tox
matrix:
include:
- os: "linux"
dist: "xenial"
python: "3.6"
- os: "linux"
dist: "xenial"
python: "3.7"
- os: "linux"
dist: "focal"
python: "3.8"
- os: "linux"
dist: "focal"
python: "3.9"
- os: "windows"
language: shell
python: "3.9"
env: "PATH=/c/python39:/c/python39/Scripts:$PATH"
before_install:
- choco install python --version=3.9.6
- cp /c/python39/python.exe /c/python39/python3.exe
script: tox -e py39

View File

@ -126,13 +126,13 @@ class DupeGuru(Broadcaster):
PICTURE_CACHE_TYPE = "sqlite" # set to 'shelve' for a ShelveCache PICTURE_CACHE_TYPE = "sqlite" # set to 'shelve' for a ShelveCache
def __init__(self, view, portable=False): def __init__(self, view):
if view.get_default(DEBUG_MODE_PREFERENCE): if view.get_default(DEBUG_MODE_PREFERENCE):
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
logging.debug("Debug mode enabled") logging.debug("Debug mode enabled")
Broadcaster.__init__(self) Broadcaster.__init__(self)
self.view = view self.view = view
self.appdata = desktop.special_folder_path(desktop.SpecialFolder.AppData, appname=self.NAME, portable=portable) self.appdata = desktop.special_folder_path(desktop.SpecialFolder.AppData, appname=self.NAME)
if not op.exists(self.appdata): if not op.exists(self.appdata):
os.makedirs(self.appdata) os.makedirs(self.appdata)
self.app_mode = AppMode.Standard self.app_mode = AppMode.Standard

View File

@ -5,8 +5,6 @@
# http://www.gnu.org/licenses/gpl-3.0.html # http://www.gnu.org/licenses/gpl-3.0.html
import time import time
import sys
import os
from hscommon.util import format_time_decimal from hscommon.util import format_time_decimal
@ -60,7 +58,3 @@ def fix_surrogate_encoding(s, encoding="utf-8"):
return s.encode(encoding, "replace").decode(encoding) return s.encode(encoding, "replace").decode(encoding)
else: else:
return s return s
def executable_folder():
return os.path.dirname(os.path.abspath(sys.argv[0]))

View File

@ -30,7 +30,7 @@ def reveal_path(path):
_reveal_path(str(path)) _reveal_path(str(path))
def special_folder_path(special_folder, appname=None, portable=False): def special_folder_path(special_folder, appname=None):
"""Returns the path of ``special_folder``. """Returns the path of ``special_folder``.
``special_folder`` is a SpecialFolder.* const. The result is the special folder for the current ``special_folder`` is a SpecialFolder.* const. The result is the special folder for the current
@ -38,7 +38,7 @@ def special_folder_path(special_folder, appname=None, portable=False):
You can override the application name with ``appname``. This argument is ingored under Qt. You can override the application name with ``appname``. This argument is ingored under Qt.
""" """
return _special_folder_path(special_folder, appname, portable=portable) return _special_folder_path(special_folder, appname)
try: try:
@ -54,7 +54,7 @@ try:
_open_path = proxy.openPath_ _open_path = proxy.openPath_
_reveal_path = proxy.revealPath_ _reveal_path = proxy.revealPath_
def _special_folder_path(special_folder, appname=None, portable=False): def _special_folder_path(special_folder, appname=None):
if special_folder == SpecialFolder.Cache: if special_folder == SpecialFolder.Cache:
base = proxy.getCachePath() base = proxy.getCachePath()
else: else:
@ -68,9 +68,6 @@ except ImportError:
try: try:
from PyQt5.QtCore import QUrl, QStandardPaths from PyQt5.QtCore import QUrl, QStandardPaths
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
from qtlib.util import getAppData
from core.util import executable_folder
from hscommon.plat import ISWINDOWS
def _open_url(url): def _open_url(url):
QDesktopServices.openUrl(QUrl(url)) QDesktopServices.openUrl(QUrl(url))
@ -82,15 +79,12 @@ except ImportError:
def _reveal_path(path): def _reveal_path(path):
_open_path(op.dirname(str(path))) _open_path(op.dirname(str(path)))
def _special_folder_path(special_folder, appname=None, portable=False): def _special_folder_path(special_folder, appname=None):
if special_folder == SpecialFolder.Cache: if special_folder == SpecialFolder.Cache:
if ISWINDOWS and portable: qtfolder = QStandardPaths.CacheLocation
folder = op.join(executable_folder(), "cache")
else: else:
folder = QStandardPaths.standardLocations(QStandardPaths.CacheLocation)[0] qtfolder = QStandardPaths.DataLocation
else: return QStandardPaths.standardLocations(qtfolder)[0]
folder = getAppData(portable)
return folder
except ImportError: except ImportError:
# We're either running tests, and these functions don't matter much or we're in a really # We're either running tests, and these functions don't matter much or we're in a really
@ -103,5 +97,5 @@ except ImportError:
def _reveal_path(path): def _reveal_path(path):
pass pass
def _special_folder_path(special_folder, appname=None, portable=False): def _special_folder_path(special_folder, appname=None):
return "/tmp" return "/tmp"

View File

@ -36,95 +36,95 @@ msgstr ""
msgid "Sending to Trash" msgid "Sending to Trash"
msgstr "" msgstr ""
#: core\app.py:290 #: core\app.py:308
msgid "A previous action is still hanging in there. You can't start a new one yet. Wait a few seconds, then try again." msgid "A previous action is still hanging in there. You can't start a new one yet. Wait a few seconds, then try again."
msgstr "" msgstr ""
#: core\app.py:300 #: core\app.py:318
msgid "No duplicates found." msgid "No duplicates found."
msgstr "" msgstr ""
#: core\app.py:315 #: core\app.py:333
msgid "All marked files were copied successfully." msgid "All marked files were copied successfully."
msgstr "" msgstr ""
#: core\app.py:316 #: core\app.py:334
msgid "All marked files were moved successfully." msgid "All marked files were moved successfully."
msgstr "" msgstr ""
#: core\app.py:317 #: core\app.py:335
msgid "All marked files were successfully sent to Trash." msgid "All marked files were successfully sent to Trash."
msgstr "" msgstr ""
#: core\app.py:323 #: core\app.py:343
msgid "Could not load file: {}" msgid "Could not load file: {}"
msgstr "" msgstr ""
#: core\app.py:379 #: core\app.py:399
msgid "'{}' already is in the list." msgid "'{}' already is in the list."
msgstr "" msgstr ""
#: core\app.py:381 #: core\app.py:401
msgid "'{}' does not exist." msgid "'{}' does not exist."
msgstr "" msgstr ""
#: core\app.py:389 #: core\app.py:410
msgid "All selected %d matches are going to be ignored in all subsequent scans. Continue?" msgid "All selected %d matches are going to be ignored in all subsequent scans. Continue?"
msgstr "" msgstr ""
#: core\app.py:463 #: core\app.py:486
msgid "Select a directory to copy marked files to" msgid "Select a directory to copy marked files to"
msgstr "" msgstr ""
#: core\app.py:465 #: core\app.py:487
msgid "Select a directory to move marked files to" msgid "Select a directory to move marked files to"
msgstr "" msgstr ""
#: core\app.py:504 #: core\app.py:527
msgid "Select a destination for your exported CSV" msgid "Select a destination for your exported CSV"
msgstr "" msgstr ""
#: core\app.py:510 core\app.py:764 core\app.py:774 #: core\app.py:534 core\app.py:803 core\app.py:813
msgid "Couldn't write to file: {}" msgid "Couldn't write to file: {}"
msgstr "" msgstr ""
#: core\app.py:533 #: core\app.py:559
msgid "You have no custom command set up. Set it up in your preferences." msgid "You have no custom command set up. Set it up in your preferences."
msgstr "" msgstr ""
#: core\app.py:691 core\app.py:703 #: core\app.py:727 core\app.py:740
msgid "You are about to remove %d files from results. Continue?" msgid "You are about to remove %d files from results. Continue?"
msgstr "" msgstr ""
#: core\app.py:739 #: core\app.py:776
msgid "{} duplicate groups were changed by the re-prioritization." msgid "{} duplicate groups were changed by the re-prioritization."
msgstr "" msgstr ""
#: core\app.py:783 #: core\app.py:823
msgid "The selected directories contain no scannable file." msgid "The selected directories contain no scannable file."
msgstr "" msgstr ""
#: core\app.py:796 #: core\app.py:837
msgid "Collecting files to scan" msgid "Collecting files to scan"
msgstr "" msgstr ""
#: core\app.py:843 #: core\app.py:893
msgid "%s (%d discarded)" msgid "%s (%d discarded)"
msgstr "" msgstr ""
#: core\engine.py:251 core\engine.py:294 #: core\engine.py:255 core\engine.py:299
msgid "0 matches found" msgid "0 matches found"
msgstr "" msgstr ""
#: core\engine.py:269 core\engine.py:306 #: core\engine.py:273 core\engine.py:307
msgid "%d matches found" msgid "%d matches found"
msgstr "" msgstr ""
#: core\gui\deletion_options.py:71 #: core\gui\deletion_options.py:73
msgid "You are sending {} file(s) to the Trash." msgid "You are sending {} file(s) to the Trash."
msgstr "" msgstr ""
#: core\gui\exclude_list_table.py:14 #: core\gui\exclude_list_table.py:15
msgid "Regular Expressions" msgid "Regular Expressions"
msgstr "" msgstr ""
@ -156,15 +156,15 @@ msgstr ""
msgid "Analyzed %d/%d pictures" msgid "Analyzed %d/%d pictures"
msgstr "" msgstr ""
#: core\pe\matchblock.py:177 #: core\pe\matchblock.py:181
msgid "Performed %d/%d chunk matches" msgid "Performed %d/%d chunk matches"
msgstr "" msgstr ""
#: core\pe\matchblock.py:185 #: core\pe\matchblock.py:191
msgid "Preparing for matching" msgid "Preparing for matching"
msgstr "" msgstr ""
#: core\pe\matchblock.py:234 #: core\pe\matchblock.py:244
msgid "Verified %d/%d matches" msgid "Verified %d/%d matches"
msgstr "" msgstr ""
@ -212,11 +212,11 @@ msgstr ""
msgid "Oldest" msgid "Oldest"
msgstr "" msgstr ""
#: core\results.py:134 #: core\results.py:144
msgid "%d / %d (%s / %s) duplicates marked." msgid "%d / %d (%s / %s) duplicates marked."
msgstr "" msgstr ""
#: core\results.py:141 #: core\results.py:151
msgid " filter: %s" msgid " filter: %s"
msgstr "" msgstr ""

View File

@ -905,11 +905,3 @@ msgstr ""
#: qt\preferences_dialog.py:286 #: qt\preferences_dialog.py:286
msgid "Display" msgid "Display"
msgstr "" msgstr ""
#: qt\se\preferences_dialog.py:70
msgid "Partially hash files bigger than"
msgstr ""
#: qt\se\preferences_dialog.py:80
msgid "MB"
msgstr ""

View File

@ -52,7 +52,7 @@ class DupeGuru(QObject):
# Enable tabs instead of separate floating windows for each dialog # Enable tabs instead of separate floating windows for each dialog
# Could be passed as an argument to this class if we wanted # Could be passed as an argument to this class if we wanted
self.use_tabs = True self.use_tabs = True
self.model = DupeGuruModel(view=self, portable=self.prefs.portable) self.model = DupeGuruModel(view=self)
self._setup() self._setup()
# --- Private # --- Private

View File

@ -29,7 +29,6 @@ class Preferences(PreferencesBase):
self.language = get("Language", self.language) self.language = get("Language", self.language)
if not self.language and trans.installed_lang: if not self.language and trans.installed_lang:
self.language = trans.installed_lang self.language = trans.installed_lang
self.portable = get("Portable", False)
self.tableFontSize = get("TableFontSize", self.tableFontSize) self.tableFontSize = get("TableFontSize", self.tableFontSize)
self.reference_bold_font = get("ReferenceBoldFont", self.reference_bold_font) self.reference_bold_font = get("ReferenceBoldFont", self.reference_bold_font)
@ -139,7 +138,6 @@ class Preferences(PreferencesBase):
set_("DestinationType", self.destination_type) set_("DestinationType", self.destination_type)
set_("CustomCommand", self.custom_command) set_("CustomCommand", self.custom_command)
set_("Language", self.language) set_("Language", self.language)
set_("Portable", self.portable)
set_("TableFontSize", self.tableFontSize) set_("TableFontSize", self.tableFontSize)
set_("ReferenceBoldFont", self.reference_bold_font) set_("ReferenceBoldFont", self.reference_bold_font)

View File

@ -4,27 +4,27 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: utf-8\n" "Content-Transfer-Encoding: utf-8\n"
#: qtlib\about_box.py:37 #: qtlib\about_box.py:43
msgid "About {}" msgid "About {}"
msgstr "" msgstr ""
#: qtlib\about_box.py:57 #: qtlib\about_box.py:65
msgid "Version {}" msgid "Version {}"
msgstr "" msgstr ""
#: qtlib\about_box.py:61 #: qtlib\about_box.py:70
msgid "Licensed under GPLv3" msgid "Licensed under GPLv3"
msgstr "" msgstr ""
#: qtlib\error_report_dialog.py:47 #: qtlib\error_report_dialog.py:49
msgid "Error Report" msgid "Error Report"
msgstr "" msgstr ""
#: qtlib\error_report_dialog.py:51 #: qtlib\error_report_dialog.py:53
msgid "Something went wrong. How about reporting the error?" msgid "Something went wrong. How about reporting the error?"
msgstr "" msgstr ""
#: qtlib\error_report_dialog.py:57 #: qtlib\error_report_dialog.py:59
msgid "" msgid ""
"Error reports should be reported as Github issues. You can copy the error traceback above and paste it in a new issue.\n" "Error reports should be reported as Github issues. You can copy the error traceback above and paste it in a new issue.\n"
"\n" "\n"
@ -35,83 +35,83 @@ msgid ""
"Although the application should continue to run after this error, it may be in an unstable state, so it is recommended that you restart the application." "Although the application should continue to run after this error, it may be in an unstable state, so it is recommended that you restart the application."
msgstr "" msgstr ""
#: qtlib\error_report_dialog.py:73 #: qtlib\error_report_dialog.py:75
msgid "Close" msgid "Close"
msgstr "" msgstr ""
#: qtlib\error_report_dialog.py:77 #: qtlib\error_report_dialog.py:79
msgid "Go to Github" msgid "Go to Github"
msgstr "" msgstr ""
#: qtlib\preferences.py:24 #: qtlib\preferences.py:23
msgid "Czech" msgid "Czech"
msgstr "" msgstr ""
#: qtlib\preferences.py:25 #: qtlib\preferences.py:24
msgid "German" msgid "German"
msgstr "" msgstr ""
#: qtlib\preferences.py:26 #: qtlib\preferences.py:25
msgid "Greek" msgid "Greek"
msgstr "" msgstr ""
#: qtlib\preferences.py:27 #: qtlib\preferences.py:26
msgid "English" msgid "English"
msgstr "" msgstr ""
#: qtlib\preferences.py:28 #: qtlib\preferences.py:27
msgid "Spanish" msgid "Spanish"
msgstr "" msgstr ""
#: qtlib\preferences.py:29 #: qtlib\preferences.py:28
msgid "French" msgid "French"
msgstr "" msgstr ""
#: qtlib\preferences.py:30 #: qtlib\preferences.py:29
msgid "Armenian" msgid "Armenian"
msgstr "" msgstr ""
#: qtlib\preferences.py:31 #: qtlib\preferences.py:30
msgid "Italian" msgid "Italian"
msgstr "" msgstr ""
#: qtlib\preferences.py:32 #: qtlib\preferences.py:31
msgid "Japanese" msgid "Japanese"
msgstr "" msgstr ""
#: qtlib\preferences.py:33 #: qtlib\preferences.py:32
msgid "Korean" msgid "Korean"
msgstr "" msgstr ""
#: qtlib\preferences.py:34 #: qtlib\preferences.py:33
msgid "Dutch" msgid "Dutch"
msgstr "" msgstr ""
#: qtlib\preferences.py:35 #: qtlib\preferences.py:34
msgid "Polish" msgid "Polish"
msgstr "" msgstr ""
#: qtlib\preferences.py:36 #: qtlib\preferences.py:35
msgid "Brazilian" msgid "Brazilian"
msgstr "" msgstr ""
#: qtlib\preferences.py:37 #: qtlib\preferences.py:36
msgid "Russian" msgid "Russian"
msgstr "" msgstr ""
#: qtlib\preferences.py:38 #: qtlib\preferences.py:37
msgid "Turkish" msgid "Turkish"
msgstr "" msgstr ""
#: qtlib\preferences.py:39 #: qtlib\preferences.py:38
msgid "Ukrainian" msgid "Ukrainian"
msgstr "" msgstr ""
#: qtlib\preferences.py:40 #: qtlib\preferences.py:39
msgid "Vietnamese" msgid "Vietnamese"
msgstr "" msgstr ""
#: qtlib\preferences.py:41 #: qtlib\preferences.py:40
msgid "Chinese (Simplified)" msgid "Chinese (Simplified)"
msgstr "" msgstr ""

View File

@ -12,7 +12,6 @@ from PyQt5.QtWidgets import QDockWidget
from hscommon.trans import trget from hscommon.trans import trget
from hscommon.util import tryint from hscommon.util import tryint
from hscommon.plat import ISWINDOWS from hscommon.plat import ISWINDOWS
from core.util import executable_folder
from os import path as op from os import path as op
@ -69,25 +68,18 @@ def adjust_after_deserialization(v):
return v return v
def create_qsettings(): def createQSettings():
# Create a QSettings instance with the correct arguments. # Create a QSettings instance with the correct arguments.
config_location = op.join(executable_folder(), "settings.ini")
if op.isfile(config_location):
settings = QSettings(config_location, QSettings.IniFormat)
settings.setValue("Portable", True)
elif ISWINDOWS:
# On windows use an ini file in the AppDataLocation instead of registry if possible as it # On windows use an ini file in the AppDataLocation instead of registry if possible as it
# makes it easier for a user to clear it out when there are issues. # makes it easier for a user to clear it out when there are issues.
locations = QStandardPaths.standardLocations(QStandardPaths.AppDataLocation) if ISWINDOWS:
if locations: Locations = QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)
settings = QSettings(op.join(locations[0], "settings.ini"), QSettings.IniFormat) if Locations:
return QSettings(op.join(Locations[0], "settings.ini"), QSettings.IniFormat)
else: else:
settings = QSettings() return QSettings()
settings.setValue("Portable", False)
else: else:
settings = QSettings() return QSettings()
settings.setValue("Portable", False)
return settings
# About QRect conversion: # About QRect conversion:
@ -101,7 +93,7 @@ class Preferences(QObject):
def __init__(self): def __init__(self):
QObject.__init__(self) QObject.__init__(self)
self.reset() self.reset()
self._settings = create_qsettings() self._settings = createQSettings()
def _load_values(self, settings, get): def _load_values(self, settings, get):
pass pass

View File

@ -12,7 +12,6 @@ import os.path as op
import os import os
import logging import logging
from core.util import executable_folder
from hscommon.util import first from hscommon.util import first
from PyQt5.QtCore import QStandardPaths from PyQt5.QtCore import QStandardPaths
@ -89,11 +88,8 @@ def setAccelKeys(menu):
action.setText(newtext) action.setText(newtext)
def getAppData(portable=False): def getAppData():
if portable: return QStandardPaths.standardLocations(QStandardPaths.DataLocation)[0]
return op.join(executable_folder(), "data")
else:
return QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)[0]
class SysWrapper(io.IOBase): class SysWrapper(io.IOBase):

View File

@ -1,4 +1,5 @@
pytest>=6,<7 pytest>=6,<7
flake8 flake8
tox-travis
black black
pyinstaller>=4.5,<5.0; sys_platform != 'linux' pyinstaller>=4.5,<5.0; sys_platform != 'linux'

4
run.py
View File

@ -16,7 +16,7 @@ from PyQt5.QtWidgets import QApplication
from hscommon.trans import install_gettext_trans_under_qt from hscommon.trans import install_gettext_trans_under_qt
from qtlib.error_report_dialog import install_excepthook from qtlib.error_report_dialog import install_excepthook
from qtlib.util import setupQtLogging from qtlib.util import setupQtLogging
from qtlib.preferences import create_qsettings from qtlib.preferences import createQSettings
from qt import dg_rc # noqa: F401 from qt import dg_rc # noqa: F401
from qt.platform import BASE_PATH from qt.platform import BASE_PATH
from core import __version__, __appname__ from core import __version__, __appname__
@ -53,7 +53,7 @@ def main():
QCoreApplication.setApplicationName(__appname__) QCoreApplication.setApplicationName(__appname__)
QCoreApplication.setApplicationVersion(__version__) QCoreApplication.setApplicationVersion(__version__)
setupQtLogging() setupQtLogging()
settings = create_qsettings() settings = createQSettings()
lang = settings.value("Language") lang = settings.value("Language")
locale_folder = op.join(BASE_PATH, "locale") locale_folder = op.join(BASE_PATH, "locale")
install_gettext_trans_under_qt(locale_folder, lang) install_gettext_trans_under_qt(locale_folder, lang)