From 10b44dbf2671d0f5dabc1d3ae8375e1084d7120f Mon Sep 17 00:00:00 2001
From: Zach K
Date: Thu, 18 Mar 2021 20:21:15 -0400
Subject: [PATCH] 1.1.1
All the ones
---
fpcurator.py | 214 ++++++++++++++++++++++++++++++++++++++++++++-----
fpcurator.spec | 33 ++++++++
help.html | 80 ------------------
tooltip.py | 152 +++++++++++++++++++++++++++++++++++
4 files changed, 380 insertions(+), 99 deletions(-)
create mode 100644 fpcurator.spec
delete mode 100644 help.html
create mode 100644 tooltip.py
diff --git a/fpcurator.py b/fpcurator.py
index 51d0b21..60c749f 100644
--- a/fpcurator.py
+++ b/fpcurator.py
@@ -16,12 +16,98 @@
try: import Levenshtein
except: pass
+try: import win32gui, win32con # Best way to hide the console, but it isn't cross-platform, so it has a try-catch.
+except: pass
+
import tkinterhtml as tkhtml
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.filedialog as tkfd
import tkinter.messagebox as tkm
+from tooltip import Tooltip
+
+HELP_HTML = """
+
+ Help
+ fpcurator is a collection of tools for performing certain curation tasks easier. There are four sub-tools available. Note that the tool may freeze while performing any task. All debug info on any task is printed to the console that can be shown by clicking "Toggle Log".
+
+ Auto Curator
+ The Auto Curator tool generates a bunch of partial curations based upon a list of urls containing the games to curate. The list of curatable websites is limited the site definitions in the "sites" folder next to the program.
+
Here are a list of options:
+
+ - Save - When checked, the auto curator will save it's progress so if it fails from an error, the tool will resume where it left off given the same urls.
+ - Use Titles - When checked, the auto curator will use the titles of curated games instead of randomly generated UUIDs as the names of the folders the curations are put into.
+ - Clear Done URLs - When checked, the auto curator will clear any urls in the list when they are curated. Errored urls will remain in the list.
+ - Notify When Done - When checked, the auto curator will show a message box when it is done curating.
+
+ Here is some basic usage steps:
+
+ - Select the options you want, specified by the list above, and set the output directory of these partial curations.
+ - Paste the urls you want to curate into the text box, one per line.
+ - Press the "Curate" button to start the curation process.
+
+
+
+ Download URLs
+ The Download URLs tool downloads and formats a list of files from a list of urls into a collection of organized folders inside the directory specified by "Output Folder". It works in a similar way to cURLsDownloader, but is powered by fpclib. Put all the urls you want to download into the textbox and press "Download".
+
Here are a list of options:
+
+ - Delete "web.archive.org" - When checked, the downloader will put all urls downloaded from the web archive back into their original domains.
+ - Keep URLVars - When checked, the downloader will append url vars present on links being downloaded to the end of the html file. This is only necessary when you have two links to the same webpage that generate different html due to the url vars.
+ - Clear Done URLs - When checked, the downloader will clear any urls in the list when they are downloaded. Errored urls will remain in the list.
+ - Notify When Done - When checked, the downloader will show a message box when it is done downloading.
+
+ Here is some basic usage steps:
+
+ - Select the options you want, specified by the list above, and set the output directory of the downloaded folders and files.
+ - Paste the urls you want to download into the text box, one per line.
+ - Press the "Download" button to start the download process.
+
+
+
+ Bulk Search Titles
+ The Bulk Search Titles tool can take a list of titles and a list of urls for those titles and bulk check how likely it is those entries are in Flashpoint. You will need to load the Flashpoint database for it to check through, in addition to providing regexes that will be used to check if entries in Flashpoint have the right Source, Publisher, or Developer that would match a title in the list. Note that this will cache the database for later use, so if you want to reload it you'll need to either delete the file "search/database.tsv" or press "Load" on the database again.
+
Here are a list of options:
+
+ - Priorities - When checked, the searcher will generate a list of numeric priorities and print them into a file named "priorities.txt" next to the program. This is mainly used for copying into a spreadsheet.
+ - Log - When checked, the searcher will generate a more human readable log displaying how likely each it is those games are in Flashpoint.
+ - Strip Subtitles - When checked, titles will be stripped of subtitles when searching for them in Flashpoint.
+ - Exact Url Matches - When unchecked, the searcher will skip checking for exact url matches for a game match in Flashpoint. Normally an exact url match is a very good indicator if a game is curated, but this is optional in case multiple games are on the same url.
+ - Use difflib - When checked, the searcher will use the default python difflib instead of the fast and efficient python-Levenshtein.
+
+ Here is some basic usage steps:
+
+ - Select the Flashpoint database, located in your Flashpoint folder under "/Data/flashpoint.sqlite".
+ - Select the options you want, specified by the list above.
+ - Type in a source regex that would match the source of any game in Flashpoint that comes from the same location as those in the list. The regex match is case-insensitive.
+ - Type in a developer/publisher regex that would match the developer/publisher of any game in Flashpoint that comes from the same location as those in the list. Note that developers/publishers are stripped of all non-alphanumeric characters (except semicolons) and are set to lowercase ("Cool-Math-Games.com" becomes "coolmathgamescom"), so the match is case-insensitive.
+ - Copy and paste the TITLES of entries to search with in the LEFT box, one per line.
+ - Copy and paste the URLS of entries to search with in the RIGHT box, one per line.
+ - Press the "Search" button to initiate the search. When the search is done the generated "log.txt" and/or "priorities.txt" files will be automatically opened if you chose to generate them.
+
+ Here's what each of the priorities mean:
+
+
+ -1 | Duplicate |
+ 5 | Exact url matches with the source of a game in Flashpoint |
+ 4.9 | Exact url matches ignoring protocol and extra source data (like Via. Wayback) |
+ 4.8 | Title matches with a game that is from the same source/developer/publisher |
+ 4.3 | Title starts the title of a game from the same source/developer/publisher (and is >10 characters long) |
+ 4.0 | Title matches with a game in Flashpoint (may not be accurate for common names of games like Chess) |
+ 3.9 | Title starts the title of a game in Flashpoint (and is >10 characters long) |
+ 3.8 | Title is in the title of a game in Flashpoint (and is >10 characters long) |
+ 3.6-3.8 | This game has a very high (>95%) metric, meaning it matches with another title that probably has 1 or 2 letters different. |
+ 3-3.6 | This game has a medium to high metric (85-95%), meaning it kind of matches with games in Flashpoint but not really. |
+ 1-3 | Basically every other metric (60-85%). 60% is the highest match of garbage letters. |
+
+
+
+
+ Wiki Data
+ The Wiki Data tool provides you with the ability to get a list of all Tags, Platforms, Games, or Animations in Flashpoint. Just select the given page you want the data of and press "Find".
+"""
+
HEADINGS = ['TABLE OF CONTENTS', 'SUMMARY', 'DUPLICATE NAMES', 'DEFINITELY IN FLASHPOINT', 'PROBABLY IN FLASHPOINT', 'MAYBE IN FLASHPOINT', 'PROBABLY NOT IN FLASHPOINT', 'DEFINITELY NOT IN FLASHPOINT']
TEXTS = {
'header': 'Search performed on %s\nDISCLAIMER: ALWAYS CHECK THE MASTER LIST AND DISCORD CHANNEL BEFORE CURATING, EVEN IF SOMETHING IS LISTED HERE AS NOT CURATED\n\n',
@@ -51,8 +137,8 @@
'p1.verylowmetric': 'Has a very low similarity metric (<75%)'
}
-TITLE = "fpcurator v1.1.0"
-ABOUT = "Created by Zach K - v1.1.0"
+TITLE = "fpcurator v1.1.1"
+ABOUT = "Created by Zach K - v1.1.1"
SITES_FOLDER = "sites"
@@ -61,6 +147,10 @@
AM_PATTERN = re.compile('[\W_]+')
AMS_PATTERN = re.compile('([^\w;]|_)+')
+MAINFRAME = None
+try: CONSOLE = win32gui.GetForegroundWindow()
+except: pass
+
def set_entry(entry, data):
entry.delete(0, "end")
entry.insert(0, data)
@@ -86,13 +176,14 @@ class Mainframe(tk.Tk):
def __init__(self):
# Create window
super().__init__()
- self.minsize(645, 600)
+ self.minsize(695, 650)
self.title(TITLE)
self.protocol("WM_DELETE_WINDOW", self.exit_window)
# Add tabs
self.tabs = ttk.Notebook(self)
self.tabs.pack(expand=True, fill="both", padx=5, pady=5)
+ self.tabs.bind("<>", self.tab_change)
self.autocurator = AutoCurator()
self.downloader = Downloader()
@@ -101,7 +192,7 @@ def __init__(self):
self.tabs.add(self.autocurator, text="Auto Curator")
self.tabs.add(self.downloader, text="Download URLs")
- self.tabs.add(self.searcher, text="Search")
+ self.tabs.add(self.searcher, text="Bulk Search Titles")
self.tabs.add(self.lister, text="Wiki Data")
# Add help and about label
@@ -112,18 +203,21 @@ def __init__(self):
label.pack(side="left")
help_button = ttk.Button(bframe, text="Help", command=self.show_help)
help_button.pack(side="left", padx=5)
+ log_button = ttk.Button(bframe, text="Toggle Log", command=self.toggle_log)
+ log_button.pack(side="left")
# Add debug level entry
self.debug_level = tk.StringVar()
self.debug_level.set(str(fpclib.DEBUG_LEVEL))
self.debug_level.trace("w", self.set_debug_level)
- dlabel = ttk.Label(bframe, text="Debug Level: ")
+ dlabel = ttk.Label(bframe, text=" Debug Level: ")
dlabel.pack(side="left")
debug_level = ttk.Entry(bframe, textvariable=self.debug_level)
debug_level.pack(side="left")
- # Exists to prevent more than one help menu from opening at a time
+ # Exists to prevent more than one of a window from opening at a time
self.help = None
+ self.log = True
# Load GUI state from last close
self.load()
@@ -132,6 +226,15 @@ def __init__(self):
self.frozen = False
self.after(100, self.check_freeze)
+ def tab_change(self, event):
+ tab = self.tabs.select()
+ if tab == ".!autocurator":
+ self.autocurator.stxt.txt.focus_set()
+ elif tab == ".!downloader":
+ self.downloader.stxt.txt.focus_set()
+ elif tab == ".!searcher":
+ self.searcher.stxta.txt.focus_set()
+
def check_freeze(self):
if self.frozen and not frozen_ui: self.unfreeze()
self.after(100, self.check_freeze)
@@ -166,6 +269,15 @@ def show_help(self):
if not self.help:
self.help = Help(self)
+ def toggle_log(self):
+ if CONSOLE:
+ if self.log:
+ win32gui.ShowWindow(CONSOLE, win32con.SW_HIDE)
+ self.log = False
+ else:
+ win32gui.ShowWindow(CONSOLE, win32con.SW_SHOW)
+ self.log = True
+
def set_debug_level(self, name, index, mode):
dl = self.debug_level.get()
try:
@@ -175,7 +287,8 @@ def set_debug_level(self, name, index, mode):
def exit_window(self):
if not frozen_ui:
- # Python can't stop a thread easily, so make sure nothing is running before closing.
+ if not self.log: self.toggle_log()
+ # TODO: Python can't stop a thread easily, so make sure nothing is running before closing.
self.save()
self.destroy()
@@ -294,13 +407,45 @@ def __init__(self, parent):
# Create htmlframe for displaying help information
txt = tkhtml.HtmlFrame(self, vertical_scrollbar="auto", horizontal_scrollbar="auto")
- with open("help.html", "r") as file: txt.set_content(file.read())
+ txt.set_content(HELP_HTML)
txt.pack(expand=True, fill="both")
def exit_window(self):
self.parent.help = None
self.destroy()
+class Log(tk.Toplevel):
+ def __init__(self, parent):
+ # Create window
+ super().__init__(bg="white")
+ self.title(TITLE + " - Log")
+ self.minsize(445, 400)
+ self.geometry("745x700")
+ self.protocol("WM_DELETE_WINDOW", self.exit_window)
+ self.parent = parent
+
+ # Create text pane for showing log
+ self.stxt = ScrolledText(self, width=10, height=10, wrap="none", state="disabled")
+ self.stxt.pack(expand=True, fill="both")
+
+ # Queue update checks
+ self.update = True
+ self.update_check()
+
+ def update_check(self):
+ if self.update:
+ txt = self.stxt.txt
+ txt["state"] = "normal"
+ txt.delete("0.0", "end")
+ txt.insert("end", LOGGER.logged())
+ txt["state"] = "disabled"
+ self.update = False
+ self.parent.after(100, self.update_check)
+
+ def exit_window(self):
+ self.parent.log = None
+ self.destroy()
+
class AutoCurator(tk.Frame):
def __init__(self):
# Create panel
@@ -340,11 +485,17 @@ def __init__(self):
#silent.pack(side="left", padx=5)
titles = tk.Checkbutton(cframe, bg="white", text="Use Titles", var=self.titles)
titles.pack(side="left")
- clear = tk.Checkbutton(cframe, bg="white", text="Clear URLs", var=self.clear)
+ clear = tk.Checkbutton(cframe, bg="white", text="Clear Done URLs", var=self.clear)
clear.pack(side="left", padx=5)
- show_done = tk.Checkbutton(cframe, bg="white", text='Show Done', var=self.show_done)
+ show_done = tk.Checkbutton(cframe, bg="white", text='Notify When Done', var=self.show_done)
show_done.pack(side="left")
+ Tooltip(save, text="When checked, the auto curator will save it's progress so if it fails from an error, the tool will resume where it left off given the same urls.")
+ #Tooltip(silent, text="")
+ Tooltip(titles, text="When checked, the auto curator will use the titles of curated games instead of randomly generated UUIDs as the names of the folders the curations are put into.")
+ Tooltip(clear, text="When checked, the auto curator will clear any urls in the list when they are curated. Errored urls will remain in the list.")
+ Tooltip(show_done, text="When checked, the auto curator will show a message box when it is done curating.")
+
# Create site definition display
dframe = tk.Frame(self, bg="white")
dframe.pack()
@@ -359,6 +510,8 @@ def __init__(self):
self.reload()
# Create panel for inputting urls
+ lbl = tk.Label(self, bg="white", text=" Put URLs to curate in this box:")
+ lbl.pack(fill="x")
self.stxt = ScrolledText(self, width=10, height=10, wrap="none")
self.stxt.pack(expand=True, fill="both", padx=5, pady=5)
@@ -474,16 +627,23 @@ def __init__(self):
self.show_done = tk.BooleanVar()
self.show_done.set(True)
- original = tk.Checkbutton(cframe, bg="white", text='Remove "web.archive.org"', var=self.original)
+ original = tk.Checkbutton(cframe, bg="white", text='Delete "web.archive.org"', var=self.original)
original.pack(side="left")
keep_vars = tk.Checkbutton(cframe, bg="white", text="Keep URLVars", var=self.keep_vars)
keep_vars.pack(side="left", padx=5)
- clear = tk.Checkbutton(cframe, bg="white", text="Clear URLs", var=self.clear)
+ clear = tk.Checkbutton(cframe, bg="white", text="Clear Done URLs", var=self.clear)
clear.pack(side="left")
- show_done = tk.Checkbutton(cframe, bg="white", text='Show Done', var=self.show_done)
+ show_done = tk.Checkbutton(cframe, bg="white", text='Notify When Done', var=self.show_done)
show_done.pack(side="left", padx=5)
+ Tooltip(original, text="When checked, the downloader will put all urls downloaded from the web archive back into their original domains.")
+ Tooltip(keep_vars, text="When checked, the downloader will append url vars present on links being downloaded to the end of the html file. This is only necessary when you have two links to the same webpage that generate different html due to the url vars.")
+ Tooltip(clear, text="When checked, the downloader will clear any urls in the list when they are downloaded. Errored urls will remain in the list.")
+ Tooltip(show_done, text="When checked, the downloader will show a message box when it is done downloading.")
+
# Create panel for inputting urls to download
+ lbl = tk.Label(self, bg="white", text=" Put URLs to download in this box:")
+ lbl.pack(fill="x")
self.stxt = ScrolledText(self, width=10, height=10, wrap="none")
self.stxt.pack(expand=True, fill="both", padx=5, pady=5)
@@ -582,7 +742,15 @@ def __init__(self):
difflib = tk.Checkbutton(cframe, bg="white", text="Use difflib", var=self.difflib)
difflib.pack(side="left")
+ Tooltip(priorities, text='When checked, the searcher will generate a list of numeric priorities and print them into a file named "priorities.txt" next to the program. This is mainly used for copying into a spreadsheet.')
+ Tooltip(log, text="When checked, the searcher will generate a more human readable log displaying how likely each it is those games are in Flashpoint.")
+ Tooltip(strip, text="When checked, titles will be stripped of subtitles when searching for them in Flashpoint.")
+ Tooltip(exact_url, text='When unchecked, the searcher will skip checking for exact url matches for a game match in Flashpoint. Normally an exact url match is a very good indicator if a game is curated, but this is optional in case multiple games are on the same url.')
+ Tooltip(difflib, text="When checked, the searcher will use the default python library difflib instead of the fast and efficient python-Levenshtein.")
+
# Panels
+ lbl = tk.Label(self, bg="white", text="Put TITLES in the LEFT box and URLS in the RIGHT.")
+ lbl.pack(fill="x")
txts = tk.Frame(self, bg="white")
txts.pack(expand=True, fill="both", padx=5, pady=(0, 5))
@@ -1122,7 +1290,7 @@ def __init__(self):
self.choice = tk.StringVar()
self.choice.set("Tags")
- c = ttk.Combobox(tframe, textvariable=self.choice, values=["Tags", "Platforms", "Game_Master_List", "Animation_Master_List"])
+ c = ttk.Combobox(tframe, textvariable=self.choice, values=["Tags", "Platforms", "Game Master List", "Animation Master List"])
c.pack(side="left")
self.find_btn = ttk.Button(tframe, text="Find", command=self.find)
@@ -1135,10 +1303,16 @@ def __init__(self):
self.stxt.pack(expand=True, fill="both", padx=5, pady=(0, 5))
def i_find(self):
- fpclib.debug("Getting all data from the {} page on the wiki", 1, self.choice.get())
txt = self.stxt.txt
txt.delete("0.0", "end")
- txt.insert("end", "\n".join(fpclib.get_fpdata(self.choice.get())))
+ try:
+ data = fpclib.get_fpdata(self.choice.get().replace(" ", "_"))
+ if data:
+ txt.insert("end", "\n".join(data))
+ else:
+ tkm.showerror(message="Failed to get data from wiki.")
+ except Exception as e:
+ tkm.showerror(message="Failed to get data from wiki.")
unfreeze()
def find(self):
@@ -1151,6 +1325,7 @@ def clear(self):
class ScrolledText(tk.Frame):
def __init__(self, parent, **kwargs):
super().__init__(parent)
+
self.txt = tk.Text(self, **kwargs)
txtV = ttk.Scrollbar(self, orient="vertical", command=self.txt.yview)
txtH = ttk.Scrollbar(self, orient="horizontal", command=self.txt.xview)
@@ -1169,6 +1344,7 @@ def __init__(self, parent, **kwargs):
if len(sys.argv) == 1:
print("[INFO] Launching fpcurator GUI variant. Launch the program with the --help flag to see command line usage.")
MAINFRAME = Mainframe()
+ MAINFRAME.toggle_log()
MAINFRAME.mainloop()
else:
# Command line args time!
@@ -1222,10 +1398,10 @@ def __init__(self, parent, **kwargs):
urls = []
for loc in args.loc:
try:
- raw = fpclib.read_lines(loc).split("@")
+ raw = fpclib.read(loc).replace("\r\n", "\n").replace("\r", "\n").split("@")
- titles.extend([url.strip() for url in raw[0] if url.strip()])
- urls.extend([url.strip() for url in raw[1] if url.strip()])
+ titles.extend([url.strip() for url in raw[0].split("\n") if url.strip()])
+ urls.extend([url.strip() for url in raw[1].split("\n") if url.strip()])
except:
fpclib.debug('[ERR] Invalid file "{}", skipping', 1, loc)
else:
diff --git a/fpcurator.spec b/fpcurator.spec
new file mode 100644
index 0000000..21e3ee5
--- /dev/null
+++ b/fpcurator.spec
@@ -0,0 +1,33 @@
+# -*- mode: python ; coding: utf-8 -*-
+
+block_cipher = None
+
+
+a = Analysis(['fpcurator.py'],
+ pathex=['C:\\Users\\Zach\\Documents\\Code\\git\\fpcurator'],
+ binaries=[],
+ datas=[],
+ hiddenimports=[],
+ hookspath=[],
+ runtime_hooks=[],
+ excludes=[],
+ win_no_prefer_redirects=False,
+ win_private_assemblies=False,
+ cipher=block_cipher,
+ noarchive=False)
+pyz = PYZ(a.pure, a.zipped_data,
+ cipher=block_cipher)
+exe = EXE(pyz,
+ a.scripts,
+ a.binaries,
+ a.zipfiles,
+ a.datas,
+ [],
+ name='fpcurator',
+ debug=False,
+ bootloader_ignore_signals=False,
+ strip=False,
+ upx=True,
+ upx_exclude=[],
+ runtime_tmpdir=None,
+ console=True )
diff --git a/help.html b/help.html
deleted file mode 100644
index 1196434..0000000
--- a/help.html
+++ /dev/null
@@ -1,80 +0,0 @@
-
-
- Help
- fpcurator is a collection of tools for performing certain curation tasks easier. There are four sub-tools available. Note that the tool may freeze while performing any task. All debug info on any task is printed to the console the program should have launched with.
-
- Auto Curator
- The Auto Curator tool generates a bunch of partial curations based upon a list of urls containing the games to curate. The list of curatable websites is limited the site definitions in the "sites" folder next to the program.
-
Here are a list of options:
-
- - Save - When checked, the auto curator will save it's progress so if it fails from an error, the tool will resume where it left off given the same urls.
- - Use Titles - When checked, the auto curator will use the titles of curated games instead of a randomly generated uuid.
- - Clear URLs - When checked, the auto curator will clear any urls in the list when they are curated. Errored urls will remain in the list.
- - Show Done - When checked, the auto curator will show a message box when it is done curating.
-
- Here is some basic usage steps:
-
- - Select the options you want, specified by the list above, and set the output directory of these partial curations.
- - Paste the urls you want to curate into the text box, one per line.
- - Press the "Curate" button to start the curation process.
-
-
-
- Download URLs
- The Download URLs tool downloads and formats a list of files from a list of urls into a collection of organized folders inside the directory specified by "Output Folder". It works in a similar way to cURLsDownloader, but is powered by fpclib. Put all the urls you want to download into the textbox and press "Download".
-
Here are a list of options:
-
- - Remove "web.archive.org" - When checked, the downloader will put all urls downloaded from the web archive back into their original domains.
- - Keep URLVars - When checked, the downloader will append url vars present on links being downloaded to the end of the html file. This is only necessary when you have two links to the same webpage that generate different html due to the url vars.
- - Clear URLs - When checked, the downloader will clear any urls in the list when they are downloaded. Errored urls will remain in the list.
- - Show Done - When checked, the downloader will show a message box when it is done downloading.
-
- Here is some basic usage steps:
-
- - Select the options you want, specified by the list above, and set the output directory of the downloaded folders and files.
- - Paste the urls you want to download into the text box, one per line.
- - Press the "Download" button to start the download process.
-
-
-
- Search
- The Search tool can take a list of titles and a list of urls for those titles and bulk check how likely it is those entries are in Flashpoint. You will need to load the Flashpoint database for it to check through, in addition to providing regexes that will be used to check if entries in Flashpoint have the right Source, Publisher, or Developer that would match a title in the list. Note that this will cache the database for later use, so if you want to reload it you'll need to either delete the file "search/database.tsv" or press "Load" on the database again.
-
Here are a list of options:
-
- - Priorities - When checked, the searcher will generate a list of numeric priorities and print them into a file named "priorities.txt" next to the program. This is mainly used for copying into a spreadsheet.
- - Log - When checked, the searcher will generate a more human readable log displaying how likely each it is those games are in Flashpoint.
- - Strip Subtitles - When checked, titles will be stripped of subtitles when searching for them in Flashpoint.
- - Exact Url Matches - When unchecked, the searcher will skip checking for exact url matches for a game match in Flashpoint. Normally an exact url match is a very good indicator if a game is curated, but this is optional in case multiple games are on the same url.
- - Use difflib - When checked, the searcher will use the default python difflib instead of the fast and efficient python-Levenshtein.
-
- Here is some basic usage steps:
-
- - Select the Flashpoint database, located in your Flashpoint folder under "/Data/flashpoint.sqlite".
- - Select the options you want, specified by the list above.
- - Type in a source regex that would match the source of any game in Flashpoint that comes from the same location as those in the list. The regex match is case-insensitive.
- - Type in a developer/publisher regex that would match the developer/publisher of any game in Flashpoint that comes from the same location as those in the list. Note that developers/publishers are stripped of all non-alphanumeric characters (except semicolons) and are set to lowercase ("Cool-Math-Games.com" becomes "coolmathgamescom"), so the match is case-insensitive.
- - Copy and paste the TITLES of entries to search with in the LEFT box, one per line.
- - Copy and paste the URLS of entries to search with in the RIGHT box, one per line.
- - Press the "Search" button to initiate the search. When the search is done the generated "log.txt" and/or "priorities.txt" files will be automatically opened if you chose to generate them.
-
- Here's what each of the priorities mean:
-
-
- -1 | Duplicate |
- 5 | Exact url matches with the source of a game in Flashpoint |
- 4.9 | Exact url matches ignoring protocol and extra source data (like Via. Wayback) |
- 4.8 | Title matches with a game that is from the same source/developer/publisher |
- 4.3 | Title starts the title of a game from the same source/developer/publisher (and is >10 characters long) |
- 4.0 | Title matches with a game in Flashpoint (may not be accurate for common names of games like Chess) |
- 3.9 | Title starts the title of a game in Flashpoint (and is >10 characters long) |
- 3.8 | Title is in the title of a game in Flashpoint (and is >10 characters long) |
- 3.6-3.8 | This game has a very high (>95%) metric, meaning it matches with another title that probably has 1 or 2 letters different. |
- 3-3.6 | This game has a medium to high metric (85-95%), meaning it kind of matches with games in Flashpoint but not really. |
- 1-3 | Basically every other metric (60-85%). 60% is the highest match of garbage letters. |
-
-
-
-
- Wiki Data
- The Wiki Data tool provides you with the ability to get a list of all Tags, Platforms, Games, or Animations in Flashpoint. Just select the given page you want the data of and press "Find".
-
\ No newline at end of file
diff --git a/tooltip.py b/tooltip.py
new file mode 100644
index 0000000..a030dbd
--- /dev/null
+++ b/tooltip.py
@@ -0,0 +1,152 @@
+from __main__ import tk
+
+class Tooltip:
+ '''
+ It creates a tooltip for a given widget as the mouse goes on it.
+
+ see:
+
+ http://stackoverflow.com/questions/3221956/
+ what-is-the-simplest-way-to-make-tooltips-
+ in-tkinter/36221216#36221216
+
+ http://www.daniweb.com/programming/software-development/
+ code/484591/a-tooltip-class-for-tkinter
+
+ - Originally written by vegaseat on 2014.09.09.
+
+ - Modified to include a delay time by Victor Zaccardo on 2016.03.25.
+
+ - Modified
+ - to correct extreme right and extreme bottom behavior,
+ - to stay inside the screen whenever the tooltip might go out on
+ the top but still the screen is higher than the tooltip,
+ - to use the more flexible mouse positioning,
+ - to add customizable background color, padding, waittime and
+ wraplength on creation
+ by Alberto Vassena on 2016.11.05.
+
+ Tested on Ubuntu 16.04/16.10, running Python 3.5.2
+
+ TODO: themes styles support
+ '''
+
+ def __init__(self, widget,
+ *,
+ bg='#FFFFFF',
+ pad=(0, 0, 0, 0),
+ text='widget info',
+ waittime=400,
+ wraplength=250):
+
+ self.waittime = waittime # in miliseconds, originally 500
+ self.wraplength = wraplength # in pixels, originally 180
+ self.widget = widget
+ self.text = text
+ self.widget.bind("", self.onEnter)
+ self.widget.bind("", self.onLeave)
+ self.widget.bind("", self.onLeave)
+ self.bg = bg
+ self.pad = pad
+ self.id = None
+ self.tw = None
+
+ def onEnter(self, event=None):
+ self.schedule()
+
+ def onLeave(self, event=None):
+ self.unschedule()
+ self.hide()
+
+ def schedule(self):
+ self.unschedule()
+ self.id = self.widget.after(self.waittime, self.show)
+
+ def unschedule(self):
+ id_ = self.id
+ self.id = None
+ if id_:
+ self.widget.after_cancel(id_)
+
+ def show(self):
+ def tip_pos_calculator(widget, label,
+ *,
+ tip_delta=(10, 5), pad=(5, 3, 5, 3)):
+
+ w = widget
+
+ s_width, s_height = w.winfo_screenwidth(), w.winfo_screenheight()
+
+ width, height = (pad[0] + label.winfo_reqwidth() + pad[2],
+ pad[1] + label.winfo_reqheight() + pad[3])
+
+ mouse_x, mouse_y = w.winfo_pointerxy()
+
+ x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
+ x2, y2 = x1 + width, y1 + height
+
+ x_delta = x2 - s_width
+ if x_delta < 0:
+ x_delta = 0
+ y_delta = y2 - s_height
+ if y_delta < 0:
+ y_delta = 0
+
+ offscreen = (x_delta, y_delta) != (0, 0)
+
+ if offscreen:
+
+ if x_delta:
+ x1 = mouse_x - tip_delta[0] - width
+
+ if y_delta:
+ y1 = mouse_y - tip_delta[1] - height
+
+ offscreen_again = y1 < 0 # out on the top
+
+ if offscreen_again:
+ # No further checks will be done.
+
+ # TIP:
+ # A further mod might automagically augment the
+ # wraplength when the tooltip is too high to be
+ # kept inside the screen.
+ y1 = 0
+
+ return x1, y1
+
+ bg = self.bg
+ pad = self.pad
+ widget = self.widget
+
+ # creates a toplevel window
+ self.tw = tk.Toplevel(widget)
+
+ # Leaves only the label and removes the app window
+ self.tw.wm_overrideredirect(True)
+
+ win = tk.Frame(self.tw,
+ background=bg,
+ borderwidth=0)
+ label = tk.Label(win,
+ text=self.text,
+ justify=tk.LEFT,
+ background=bg,
+ relief=tk.SOLID,
+ borderwidth=1,
+ wraplength=self.wraplength)
+
+ label.grid(padx=(pad[0], pad[2]),
+ pady=(pad[1], pad[3]),
+ sticky=tk.NSEW)
+ win.grid()
+
+ x, y = tip_pos_calculator(widget, label)
+
+ self.tw.wm_geometry("+%d+%d" % (x, y))
+
+ def hide(self):
+ tw = self.tw
+ if tw:
+ tw.destroy()
+ self.tw = None
\ No newline at end of file