mirror of
https://github.com/arsenetar/dupeguru.git
synced 2025-05-08 09:49:51 +00:00
Compare commits
3 Commits
06eca11f0b
...
5a4958cff9
Author | SHA1 | Date | |
---|---|---|---|
5a4958cff9 | |||
be10b462fc | |||
d62b13bcdb |
27
.travis.yml
27
.travis.yml
@ -1,27 +0,0 @@
|
||||
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
|
@ -126,13 +126,13 @@ class DupeGuru(Broadcaster):
|
||||
|
||||
PICTURE_CACHE_TYPE = "sqlite" # set to 'shelve' for a ShelveCache
|
||||
|
||||
def __init__(self, view):
|
||||
def __init__(self, view, portable=False):
|
||||
if view.get_default(DEBUG_MODE_PREFERENCE):
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
logging.debug("Debug mode enabled")
|
||||
Broadcaster.__init__(self)
|
||||
self.view = view
|
||||
self.appdata = desktop.special_folder_path(desktop.SpecialFolder.AppData, appname=self.NAME)
|
||||
self.appdata = desktop.special_folder_path(desktop.SpecialFolder.AppData, appname=self.NAME, portable=portable)
|
||||
if not op.exists(self.appdata):
|
||||
os.makedirs(self.appdata)
|
||||
self.app_mode = AppMode.Standard
|
||||
|
@ -5,6 +5,8 @@
|
||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
from hscommon.util import format_time_decimal
|
||||
|
||||
@ -58,3 +60,7 @@ def fix_surrogate_encoding(s, encoding="utf-8"):
|
||||
return s.encode(encoding, "replace").decode(encoding)
|
||||
else:
|
||||
return s
|
||||
|
||||
|
||||
def executable_folder():
|
||||
return os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||
|
@ -30,7 +30,7 @@ def reveal_path(path):
|
||||
_reveal_path(str(path))
|
||||
|
||||
|
||||
def special_folder_path(special_folder, appname=None):
|
||||
def special_folder_path(special_folder, appname=None, portable=False):
|
||||
"""Returns the path of ``special_folder``.
|
||||
|
||||
``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):
|
||||
|
||||
You can override the application name with ``appname``. This argument is ingored under Qt.
|
||||
"""
|
||||
return _special_folder_path(special_folder, appname)
|
||||
return _special_folder_path(special_folder, appname, portable=portable)
|
||||
|
||||
|
||||
try:
|
||||
@ -54,7 +54,7 @@ try:
|
||||
_open_path = proxy.openPath_
|
||||
_reveal_path = proxy.revealPath_
|
||||
|
||||
def _special_folder_path(special_folder, appname=None):
|
||||
def _special_folder_path(special_folder, appname=None, portable=False):
|
||||
if special_folder == SpecialFolder.Cache:
|
||||
base = proxy.getCachePath()
|
||||
else:
|
||||
@ -68,6 +68,9 @@ except ImportError:
|
||||
try:
|
||||
from PyQt5.QtCore import QUrl, QStandardPaths
|
||||
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):
|
||||
QDesktopServices.openUrl(QUrl(url))
|
||||
@ -79,12 +82,15 @@ except ImportError:
|
||||
def _reveal_path(path):
|
||||
_open_path(op.dirname(str(path)))
|
||||
|
||||
def _special_folder_path(special_folder, appname=None):
|
||||
def _special_folder_path(special_folder, appname=None, portable=False):
|
||||
if special_folder == SpecialFolder.Cache:
|
||||
qtfolder = QStandardPaths.CacheLocation
|
||||
if ISWINDOWS and portable:
|
||||
folder = op.join(executable_folder(), "cache")
|
||||
else:
|
||||
qtfolder = QStandardPaths.DataLocation
|
||||
return QStandardPaths.standardLocations(qtfolder)[0]
|
||||
folder = QStandardPaths.standardLocations(QStandardPaths.CacheLocation)[0]
|
||||
else:
|
||||
folder = getAppData(portable)
|
||||
return folder
|
||||
|
||||
except ImportError:
|
||||
# We're either running tests, and these functions don't matter much or we're in a really
|
||||
@ -97,5 +103,5 @@ except ImportError:
|
||||
def _reveal_path(path):
|
||||
pass
|
||||
|
||||
def _special_folder_path(special_folder, appname=None):
|
||||
def _special_folder_path(special_folder, appname=None, portable=False):
|
||||
return "/tmp"
|
||||
|
@ -36,95 +36,95 @@ msgstr ""
|
||||
msgid "Sending to Trash"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:308
|
||||
#: core\app.py:290
|
||||
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 ""
|
||||
|
||||
#: core\app.py:318
|
||||
#: core\app.py:300
|
||||
msgid "No duplicates found."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:333
|
||||
#: core\app.py:315
|
||||
msgid "All marked files were copied successfully."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:334
|
||||
#: core\app.py:316
|
||||
msgid "All marked files were moved successfully."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:335
|
||||
#: core\app.py:317
|
||||
msgid "All marked files were successfully sent to Trash."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:343
|
||||
#: core\app.py:323
|
||||
msgid "Could not load file: {}"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:399
|
||||
#: core\app.py:379
|
||||
msgid "'{}' already is in the list."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:401
|
||||
#: core\app.py:381
|
||||
msgid "'{}' does not exist."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:410
|
||||
#: core\app.py:389
|
||||
msgid "All selected %d matches are going to be ignored in all subsequent scans. Continue?"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:486
|
||||
#: core\app.py:463
|
||||
msgid "Select a directory to copy marked files to"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:487
|
||||
#: core\app.py:465
|
||||
msgid "Select a directory to move marked files to"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:527
|
||||
#: core\app.py:504
|
||||
msgid "Select a destination for your exported CSV"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:534 core\app.py:803 core\app.py:813
|
||||
#: core\app.py:510 core\app.py:764 core\app.py:774
|
||||
msgid "Couldn't write to file: {}"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:559
|
||||
#: core\app.py:533
|
||||
msgid "You have no custom command set up. Set it up in your preferences."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:727 core\app.py:740
|
||||
#: core\app.py:691 core\app.py:703
|
||||
msgid "You are about to remove %d files from results. Continue?"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:776
|
||||
#: core\app.py:739
|
||||
msgid "{} duplicate groups were changed by the re-prioritization."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:823
|
||||
#: core\app.py:783
|
||||
msgid "The selected directories contain no scannable file."
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:837
|
||||
#: core\app.py:796
|
||||
msgid "Collecting files to scan"
|
||||
msgstr ""
|
||||
|
||||
#: core\app.py:893
|
||||
#: core\app.py:843
|
||||
msgid "%s (%d discarded)"
|
||||
msgstr ""
|
||||
|
||||
#: core\engine.py:255 core\engine.py:299
|
||||
#: core\engine.py:251 core\engine.py:294
|
||||
msgid "0 matches found"
|
||||
msgstr ""
|
||||
|
||||
#: core\engine.py:273 core\engine.py:307
|
||||
#: core\engine.py:269 core\engine.py:306
|
||||
msgid "%d matches found"
|
||||
msgstr ""
|
||||
|
||||
#: core\gui\deletion_options.py:73
|
||||
#: core\gui\deletion_options.py:71
|
||||
msgid "You are sending {} file(s) to the Trash."
|
||||
msgstr ""
|
||||
|
||||
#: core\gui\exclude_list_table.py:15
|
||||
#: core\gui\exclude_list_table.py:14
|
||||
msgid "Regular Expressions"
|
||||
msgstr ""
|
||||
|
||||
@ -156,15 +156,15 @@ msgstr ""
|
||||
msgid "Analyzed %d/%d pictures"
|
||||
msgstr ""
|
||||
|
||||
#: core\pe\matchblock.py:181
|
||||
#: core\pe\matchblock.py:177
|
||||
msgid "Performed %d/%d chunk matches"
|
||||
msgstr ""
|
||||
|
||||
#: core\pe\matchblock.py:191
|
||||
#: core\pe\matchblock.py:185
|
||||
msgid "Preparing for matching"
|
||||
msgstr ""
|
||||
|
||||
#: core\pe\matchblock.py:244
|
||||
#: core\pe\matchblock.py:234
|
||||
msgid "Verified %d/%d matches"
|
||||
msgstr ""
|
||||
|
||||
@ -212,11 +212,11 @@ msgstr ""
|
||||
msgid "Oldest"
|
||||
msgstr ""
|
||||
|
||||
#: core\results.py:144
|
||||
#: core\results.py:134
|
||||
msgid "%d / %d (%s / %s) duplicates marked."
|
||||
msgstr ""
|
||||
|
||||
#: core\results.py:151
|
||||
#: core\results.py:141
|
||||
msgid " filter: %s"
|
||||
msgstr ""
|
||||
|
||||
|
@ -905,3 +905,11 @@ msgstr ""
|
||||
#: qt\preferences_dialog.py:286
|
||||
msgid "Display"
|
||||
msgstr ""
|
||||
|
||||
#: qt\se\preferences_dialog.py:70
|
||||
msgid "Partially hash files bigger than"
|
||||
msgstr ""
|
||||
|
||||
#: qt\se\preferences_dialog.py:80
|
||||
msgid "MB"
|
||||
msgstr ""
|
||||
|
@ -52,7 +52,7 @@ class DupeGuru(QObject):
|
||||
# Enable tabs instead of separate floating windows for each dialog
|
||||
# Could be passed as an argument to this class if we wanted
|
||||
self.use_tabs = True
|
||||
self.model = DupeGuruModel(view=self)
|
||||
self.model = DupeGuruModel(view=self, portable=self.prefs.portable)
|
||||
self._setup()
|
||||
|
||||
# --- Private
|
||||
|
@ -29,6 +29,7 @@ class Preferences(PreferencesBase):
|
||||
self.language = get("Language", self.language)
|
||||
if not self.language and trans.installed_lang:
|
||||
self.language = trans.installed_lang
|
||||
self.portable = get("Portable", False)
|
||||
|
||||
self.tableFontSize = get("TableFontSize", self.tableFontSize)
|
||||
self.reference_bold_font = get("ReferenceBoldFont", self.reference_bold_font)
|
||||
@ -138,6 +139,7 @@ class Preferences(PreferencesBase):
|
||||
set_("DestinationType", self.destination_type)
|
||||
set_("CustomCommand", self.custom_command)
|
||||
set_("Language", self.language)
|
||||
set_("Portable", self.portable)
|
||||
|
||||
set_("TableFontSize", self.tableFontSize)
|
||||
set_("ReferenceBoldFont", self.reference_bold_font)
|
||||
|
@ -4,27 +4,27 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: utf-8\n"
|
||||
|
||||
#: qtlib\about_box.py:43
|
||||
#: qtlib\about_box.py:37
|
||||
msgid "About {}"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\about_box.py:65
|
||||
#: qtlib\about_box.py:57
|
||||
msgid "Version {}"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\about_box.py:70
|
||||
#: qtlib\about_box.py:61
|
||||
msgid "Licensed under GPLv3"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\error_report_dialog.py:49
|
||||
#: qtlib\error_report_dialog.py:47
|
||||
msgid "Error Report"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\error_report_dialog.py:53
|
||||
#: qtlib\error_report_dialog.py:51
|
||||
msgid "Something went wrong. How about reporting the error?"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\error_report_dialog.py:59
|
||||
#: qtlib\error_report_dialog.py:57
|
||||
msgid ""
|
||||
"Error reports should be reported as Github issues. You can copy the error traceback above and paste it in a new issue.\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."
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\error_report_dialog.py:75
|
||||
#: qtlib\error_report_dialog.py:73
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\error_report_dialog.py:79
|
||||
#: qtlib\error_report_dialog.py:77
|
||||
msgid "Go to Github"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:23
|
||||
#: qtlib\preferences.py:24
|
||||
msgid "Czech"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:24
|
||||
#: qtlib\preferences.py:25
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:25
|
||||
#: qtlib\preferences.py:26
|
||||
msgid "Greek"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:26
|
||||
#: qtlib\preferences.py:27
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:27
|
||||
#: qtlib\preferences.py:28
|
||||
msgid "Spanish"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:28
|
||||
#: qtlib\preferences.py:29
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:29
|
||||
#: qtlib\preferences.py:30
|
||||
msgid "Armenian"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:30
|
||||
#: qtlib\preferences.py:31
|
||||
msgid "Italian"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:31
|
||||
#: qtlib\preferences.py:32
|
||||
msgid "Japanese"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:32
|
||||
#: qtlib\preferences.py:33
|
||||
msgid "Korean"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:33
|
||||
#: qtlib\preferences.py:34
|
||||
msgid "Dutch"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:34
|
||||
#: qtlib\preferences.py:35
|
||||
msgid "Polish"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:35
|
||||
#: qtlib\preferences.py:36
|
||||
msgid "Brazilian"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:36
|
||||
#: qtlib\preferences.py:37
|
||||
msgid "Russian"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:37
|
||||
#: qtlib\preferences.py:38
|
||||
msgid "Turkish"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:38
|
||||
#: qtlib\preferences.py:39
|
||||
msgid "Ukrainian"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:39
|
||||
#: qtlib\preferences.py:40
|
||||
msgid "Vietnamese"
|
||||
msgstr ""
|
||||
|
||||
#: qtlib\preferences.py:40
|
||||
#: qtlib\preferences.py:41
|
||||
msgid "Chinese (Simplified)"
|
||||
msgstr ""
|
||||
|
||||
|
@ -12,6 +12,7 @@ from PyQt5.QtWidgets import QDockWidget
|
||||
from hscommon.trans import trget
|
||||
from hscommon.util import tryint
|
||||
from hscommon.plat import ISWINDOWS
|
||||
from core.util import executable_folder
|
||||
|
||||
from os import path as op
|
||||
|
||||
@ -68,18 +69,25 @@ def adjust_after_deserialization(v):
|
||||
return v
|
||||
|
||||
|
||||
def createQSettings():
|
||||
def create_qsettings():
|
||||
# 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
|
||||
# makes it easier for a user to clear it out when there are issues.
|
||||
if ISWINDOWS:
|
||||
Locations = QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)
|
||||
if Locations:
|
||||
return QSettings(op.join(Locations[0], "settings.ini"), QSettings.IniFormat)
|
||||
locations = QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)
|
||||
if locations:
|
||||
settings = QSettings(op.join(locations[0], "settings.ini"), QSettings.IniFormat)
|
||||
else:
|
||||
return QSettings()
|
||||
settings = QSettings()
|
||||
settings.setValue("Portable", False)
|
||||
else:
|
||||
return QSettings()
|
||||
settings = QSettings()
|
||||
settings.setValue("Portable", False)
|
||||
return settings
|
||||
|
||||
|
||||
# About QRect conversion:
|
||||
@ -93,7 +101,7 @@ class Preferences(QObject):
|
||||
def __init__(self):
|
||||
QObject.__init__(self)
|
||||
self.reset()
|
||||
self._settings = createQSettings()
|
||||
self._settings = create_qsettings()
|
||||
|
||||
def _load_values(self, settings, get):
|
||||
pass
|
||||
|
@ -12,6 +12,7 @@ import os.path as op
|
||||
import os
|
||||
import logging
|
||||
|
||||
from core.util import executable_folder
|
||||
from hscommon.util import first
|
||||
|
||||
from PyQt5.QtCore import QStandardPaths
|
||||
@ -88,8 +89,11 @@ def setAccelKeys(menu):
|
||||
action.setText(newtext)
|
||||
|
||||
|
||||
def getAppData():
|
||||
return QStandardPaths.standardLocations(QStandardPaths.DataLocation)[0]
|
||||
def getAppData(portable=False):
|
||||
if portable:
|
||||
return op.join(executable_folder(), "data")
|
||||
else:
|
||||
return QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)[0]
|
||||
|
||||
|
||||
class SysWrapper(io.IOBase):
|
||||
|
@ -1,5 +1,4 @@
|
||||
pytest>=6,<7
|
||||
flake8
|
||||
tox-travis
|
||||
black
|
||||
pyinstaller>=4.5,<5.0; sys_platform != 'linux'
|
4
run.py
4
run.py
@ -16,7 +16,7 @@ from PyQt5.QtWidgets import QApplication
|
||||
from hscommon.trans import install_gettext_trans_under_qt
|
||||
from qtlib.error_report_dialog import install_excepthook
|
||||
from qtlib.util import setupQtLogging
|
||||
from qtlib.preferences import createQSettings
|
||||
from qtlib.preferences import create_qsettings
|
||||
from qt import dg_rc # noqa: F401
|
||||
from qt.platform import BASE_PATH
|
||||
from core import __version__, __appname__
|
||||
@ -53,7 +53,7 @@ def main():
|
||||
QCoreApplication.setApplicationName(__appname__)
|
||||
QCoreApplication.setApplicationVersion(__version__)
|
||||
setupQtLogging()
|
||||
settings = createQSettings()
|
||||
settings = create_qsettings()
|
||||
lang = settings.value("Language")
|
||||
locale_folder = op.join(BASE_PATH, "locale")
|
||||
install_gettext_trans_under_qt(locale_folder, lang)
|
||||
|
Loading…
x
Reference in New Issue
Block a user