2016-06-01 01:43:24 +00:00
|
|
|
# Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
|
|
|
|
#
|
|
|
|
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
|
|
# which should be included with this package. The terms are also available at
|
|
|
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
|
|
|
|
|
|
import time
|
2021-08-18 02:04:09 +00:00
|
|
|
import sys
|
|
|
|
import os
|
2022-03-28 02:06:03 +00:00
|
|
|
import urllib.request
|
|
|
|
import urllib.error
|
|
|
|
import json
|
|
|
|
import semantic_version
|
|
|
|
import logging
|
|
|
|
from typing import Union
|
2016-06-01 01:43:24 +00:00
|
|
|
|
|
|
|
from hscommon.util import format_time_decimal
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2016-06-01 01:43:24 +00:00
|
|
|
def format_timestamp(t, delta):
|
|
|
|
if delta:
|
|
|
|
return format_time_decimal(t)
|
|
|
|
else:
|
|
|
|
if t > 0:
|
2020-01-01 02:16:27 +00:00
|
|
|
return time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(t))
|
2016-06-01 01:43:24 +00:00
|
|
|
else:
|
2020-01-01 02:16:27 +00:00
|
|
|
return "---"
|
|
|
|
|
2016-06-01 01:43:24 +00:00
|
|
|
|
|
|
|
def format_words(w):
|
|
|
|
def do_format(w):
|
|
|
|
if isinstance(w, list):
|
2020-01-01 02:16:27 +00:00
|
|
|
return "(%s)" % ", ".join(do_format(item) for item in w)
|
2016-06-01 01:43:24 +00:00
|
|
|
else:
|
2020-01-01 02:16:27 +00:00
|
|
|
return w.replace("\n", " ")
|
|
|
|
|
|
|
|
return ", ".join(do_format(item) for item in w)
|
2016-06-01 01:43:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
def format_perc(p):
|
|
|
|
return "%0.0f" % p
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2016-06-01 01:43:24 +00:00
|
|
|
def format_dupe_count(c):
|
2020-01-01 02:16:27 +00:00
|
|
|
return str(c) if c else "---"
|
|
|
|
|
2016-06-01 01:43:24 +00:00
|
|
|
|
|
|
|
def cmp_value(dupe, attrname):
|
2020-01-01 02:16:27 +00:00
|
|
|
value = getattr(dupe, attrname, "")
|
2016-06-01 01:43:24 +00:00
|
|
|
return value.lower() if isinstance(value, str) else value
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
|
|
|
def fix_surrogate_encoding(s, encoding="utf-8"):
|
2016-06-01 01:43:24 +00:00
|
|
|
# ref #210. It's possible to end up with file paths that, while correct unicode strings, are
|
|
|
|
# decoded with the 'surrogateescape' option, which make the string unencodable to utf-8. We fix
|
|
|
|
# these strings here by trying to encode them and, if it fails, we do an encode/decode dance
|
|
|
|
# to remove the problematic characters. This dance is *lossy* but there's not much we can do
|
|
|
|
# because if we end up with this type of string, it means that we don't know the encoding of the
|
|
|
|
# underlying filesystem that brought them. Don't use this for strings you're going to re-use in
|
|
|
|
# fs-related functions because you're going to lose your path (it's going to change). Use this
|
|
|
|
# if you need to export the path somewhere else, outside of the unicode realm.
|
|
|
|
# See http://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/
|
|
|
|
try:
|
|
|
|
s.encode(encoding)
|
|
|
|
except UnicodeEncodeError:
|
2020-01-01 02:16:27 +00:00
|
|
|
return s.encode(encoding, "replace").decode(encoding)
|
2016-06-01 01:43:24 +00:00
|
|
|
else:
|
|
|
|
return s
|
2021-08-18 02:04:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
def executable_folder():
|
|
|
|
return os.path.dirname(os.path.abspath(sys.argv[0]))
|
2022-03-28 02:06:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
def check_for_update(current_version: str, include_prerelease: bool = False) -> Union[None, dict]:
|
|
|
|
request = urllib.request.Request(
|
|
|
|
"https://api.github.com/repos/arsenetar/dupeguru/releases",
|
|
|
|
headers={"Accept": "application/vnd.github.v3+json"},
|
|
|
|
)
|
|
|
|
try:
|
|
|
|
with urllib.request.urlopen(request) as response:
|
|
|
|
if response.status != 200:
|
|
|
|
logging.warn(f"Error retriving updates. Status: {response.status}")
|
|
|
|
return None
|
|
|
|
try:
|
|
|
|
response_json = json.loads(response.read())
|
|
|
|
except json.JSONDecodeError as ex:
|
|
|
|
logging.warn(f"Error parsing updates. {ex.msg}")
|
|
|
|
return None
|
|
|
|
except urllib.error.URLError as ex:
|
|
|
|
logging.warn(f"Error retriving updates. {ex.reason}")
|
|
|
|
return None
|
|
|
|
new_version = semantic_version.Version(current_version)
|
|
|
|
new_url = None
|
|
|
|
for release in response_json:
|
|
|
|
release_version = semantic_version.Version(release["name"])
|
|
|
|
if new_version < release_version and (include_prerelease or not release_version.prerelease):
|
|
|
|
new_version = release_version
|
|
|
|
new_url = release["html_url"]
|
|
|
|
if new_url is not None:
|
|
|
|
return {"version": new_version, "url": new_url}
|
|
|
|
else:
|
|
|
|
return None
|