182 lines
7.6 KiB
Python
182 lines
7.6 KiB
Python
"""
|
|
Maintenance of inspirations.md and synchronization with the inspirations in the entries.
|
|
"""
|
|
|
|
# TODO search fandom
|
|
# TODO which inspirations have wikipedia entries with open source games category by aren't included
|
|
|
|
import time
|
|
from utils import osg, osg_ui, osg_wikipedia, constants as c
|
|
|
|
valid_duplicates = ('Age of Empires', 'ARMA', 'Catacomb', 'Civilization', 'Company of Heroes', 'Descent', 'Duke Nukem', 'Dungeon Keeper',
|
|
'Final Fantasy', 'Heroes of Might and Magic', 'Jazz Jackrabbit', 'Marathon', 'Master of Orion', 'Quake',
|
|
'RollerCoaster Tycoon', 'Star Wars Jedi Knight', 'The Settlers', 'Ultima', 'Ship Simulator', 'Prince of Persia',
|
|
'Panzer General', 'LBreakout', 'Jagged Alliance')
|
|
|
|
|
|
class InspirationMaintainer:
|
|
|
|
def __init__(self):
|
|
self.inspirations = None
|
|
self.entries = None
|
|
|
|
def read_inspirations(self):
|
|
self.inspirations = osg.read_inspirations()
|
|
print('{} inspirations read'.format(len(self.inspirations)))
|
|
|
|
def write_inspirations(self):
|
|
if not self.inspirations:
|
|
print('inspirations not yet loaded')
|
|
return
|
|
osg.write_inspirations(self.inspirations)
|
|
print('inspirations written')
|
|
|
|
def check_for_duplicates(self):
|
|
if not self.inspirations:
|
|
print('inspirations not yet loaded')
|
|
return
|
|
start_time = time.process_time()
|
|
inspiration_names = list(self.inspirations.keys())
|
|
for index, name in enumerate(inspiration_names):
|
|
for other_name in inspiration_names[index + 1:]:
|
|
if any((name.startswith(x) and other_name.startswith(x) for x in valid_duplicates)):
|
|
continue
|
|
if osg.name_similarity(str.casefold(name), str.casefold(other_name)) > 0.9:
|
|
print(' {} - {} is similar'.format(name, other_name))
|
|
print('duplicates checked took {:.1f}s'.format(time.process_time()-start_time))
|
|
|
|
def check_for_orphans(self):
|
|
if not self.inspirations:
|
|
print('inspirations not yet loaded')
|
|
return
|
|
for inspiration in self.inspirations.values():
|
|
if not inspiration['Inspired entries']:
|
|
print(' {} has no inspired entries'.format(inspiration['Name']))
|
|
print('orphanes checked')
|
|
|
|
def check_for_missing_inspirations_in_entries(self):
|
|
if not self.inspirations:
|
|
print('inspirations not yet loaded')
|
|
return
|
|
if not self.entries:
|
|
print('entries not yet loaded')
|
|
return
|
|
for inspiration in self.inspirations.values():
|
|
inspiration_name = inspiration['Name']
|
|
for entry_name in inspiration['Inspired entries']:
|
|
x = [x for x in self.entries if x['Title'] == entry_name]
|
|
assert len(x) <= 1
|
|
if not x:
|
|
print('Entry "{}" listed in inspiration "{}" but this entry does not exist'.format(entry_name, inspiration_name))
|
|
else:
|
|
entry = x[0]
|
|
if 'Inspiration' not in entry or inspiration_name not in entry['Inspiration']:
|
|
print('Entry "{}" listed in inspiration "{}" but not listed in this entry'.format(entry_name, inspiration_name))
|
|
print('missed inspirations checked')
|
|
|
|
def check_for_wikipedia_links(self):
|
|
if not self.inspirations:
|
|
print('inspirations not yet loaded')
|
|
return
|
|
for inspiration in self.inspirations.values():
|
|
if 'Included' in inspiration:
|
|
continue
|
|
if 'Media' in inspiration and any(('https://en.wikipedia.org/wiki/' in x for x in inspiration['Media'])):
|
|
continue
|
|
name = inspiration['Name']
|
|
# search in wikipedia
|
|
results = osg_wikipedia.search(inspiration['Name'])
|
|
|
|
# throw out all (disambiguation) pages
|
|
results = [r for r in results if not any(x in r for x in ('disambiguation', 'film'))]
|
|
|
|
# throw out those too dissimilar
|
|
results = [r for r in results if osg.name_similarity(str.casefold(inspiration['Name']), str.casefold(r)) > 0.6]
|
|
|
|
# get pages for the remaining
|
|
pages = osg_wikipedia.pages(results)
|
|
|
|
# throw out those that are no video games
|
|
pages = [page for page in pages if any('video games' in category for category in page.categories)]
|
|
|
|
# sort by similarity to title and only keep highest
|
|
pages.sort(key=lambda page: osg.name_similarity(str.casefold(name), str.casefold(page.title)))
|
|
pages = pages[:min(1, len(pages))]
|
|
|
|
# if there is still one left, use it
|
|
if pages:
|
|
url = pages[0].url
|
|
inspiration['Media'] = inspiration.get('Media', []) + [url]
|
|
print('{} : {}'.format(name, url))
|
|
|
|
def update_included_entries(self):
|
|
if not self.inspirations:
|
|
print('inspirations not yet loaded')
|
|
return
|
|
if not self.entries:
|
|
print('entries not yet loaded')
|
|
return
|
|
# get all entry names
|
|
entry_names = [entry['Title'] for entry in self.entries]
|
|
# loop over all inspirations
|
|
for inspiration in self.inspirations.values():
|
|
name = inspiration['Name']
|
|
included = name in entry_names and name not in inspiration['Inspired entries']
|
|
if included:
|
|
if 'Included' not in inspiration:
|
|
print('{} is included but was not marked as such'.format(name))
|
|
for field in c.optional_inspiration_fields:
|
|
if field in inspiration:
|
|
del inspiration[field]
|
|
inspiration['Included'] = 'Yes'
|
|
elif 'Included' in inspiration:
|
|
print('{} was marked as included but is not anymore'.format(name))
|
|
del inspiration['Included']
|
|
|
|
def update_inspired_entries(self):
|
|
if not self.inspirations:
|
|
print('inspirations not yet loaded')
|
|
return
|
|
if not self.entries:
|
|
print('entries not yet loaded')
|
|
return
|
|
# loop over all inspirations and delete inspired entries
|
|
for inspiration in self.inspirations.values():
|
|
inspiration['Inspired entries'] = []
|
|
# loop over all entries and add to inspirations of entry
|
|
for entry in self.entries:
|
|
entry_name = entry['Title']
|
|
for inspiration in entry.get('Inspiration', []):
|
|
inspiration = inspiration.value
|
|
if inspiration in self.inspirations:
|
|
self.inspirations[inspiration]['Inspired entries'].append(entry_name)
|
|
else:
|
|
self.inspirations[inspiration] = {'Name': inspiration, 'Inspired entries': [entry_name]}
|
|
print('inspired entries updated')
|
|
|
|
def read_entries(self):
|
|
self.entries = osg.read_entries()
|
|
print('{} entries read'.format(len(self.entries)))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
m = InspirationMaintainer()
|
|
|
|
actions = {
|
|
'Read inspirations': m.read_inspirations,
|
|
'Write inspirations': m.write_inspirations,
|
|
'Check for duplicates': m.check_for_duplicates,
|
|
'Check for orphans': m.check_for_orphans,
|
|
'Check for inspirations not listed': m.check_for_missing_inspirations_in_entries,
|
|
'Check for wikipedia links': m.check_for_wikipedia_links,
|
|
'Update included entries': m.update_included_entries,
|
|
'Update inspirations from entries': m.update_inspired_entries,
|
|
'Read entries': m.read_entries
|
|
}
|
|
|
|
osg_ui.run_simple_button_app('Maintenance inspirations', actions)
|
|
|
|
|
|
|