def load_html_templates(): html = namedtuple('HTMLTemplates', 'entry index_page tags progress') path = lambda fname: local_path(join('templates', fname)) return html(read_file(path('entry_template.html')), read_file(path('index_page_template.html')), read_file(path('tags_template.html')), read_file(path('progress_template.html')))
def load_html_templates(): path = lambda fname: local_path(join('templates', fname)) return { 'entry': read_file(path('entry_template.html')), 'page': read_file(path('index_page_template.html')), 'tags': read_file(path('tags_template.html')) }
def __init__(self, configdir, activation_event, dry_run): super().__init__() self.setWindowTitle('Nomia') if configdir: self.configdir = configdir else: self.configdir = join(getenv('HOME'), '.config', 'nomia') activation_event.connect(self.reload_settings) self.force_quit_flag = False # Create layouts self.stack = QtGui.QStackedLayout(self) # Index viewer self.index_viewer = IndexFrame(self, dry_run, self.configdir) self.stack.addWidget(self.index_viewer) # Popup viewer self.popup_viewer = FileViewer(self) self.stack.addWidget(self.popup_viewer) self.popuphomekey = QtGui.QShortcut(QtGui.QKeySequence(), self.popup_viewer, self.show_index) # Load settings self.defaultstyle = read_json(local_path('defaultstyle.json')) self.css_template = read_file(local_path(join('templates','template.css'))) self.index_css_template = read_file(local_path(join('templates','index_page.css'))) self.settings, self.style = {}, {} self.reload_settings() self.index_viewer.populate_view() # Misc #self.connect_signals() self.show()
def cmd_revision_control(self, arg): fname = self.current_page_path() firstline, _ = read_file(fname).split('\n', 1) jsondata = json.loads(firstline) if arg == '+': if self.revisionactive: self.terminal.error('Can\'t create new revision when viewing an old one') return saved = self.save_tab() if saved: # Do this again in case something got saved before _, data = read_file(fname).split('\n', 1) f = join(self.root, fname) rev = jsondata['revision'] shutil.copy2(f, f + '.rev{}'.format(rev)) jsondata['revision'] += 1 jsondata['revision created'] = datetime.now().isoformat() write_file(f, json.dumps(jsondata) + '\n' + data) self.terminal.print_('Revision increased to {}'.format(rev + 1)) # Show a certain revision elif arg.isdigit(): revfname = join(self.root, fname + '.rev{}'.format(arg)) if not os.path.exists(revfname): self.terminal.error('Revision {} not found'.format(arg)) return saved = self.save_tab() if not saved: return try: _, data = read_file(revfname).split('\n', 1) except Exception as e: print(str(e)) self.error('Something went wrong when loading the revision') else: self.textarea.setPlainText(data) self.textarea.document().setModified(False) self.revisionactive = True self.revisionnotice.setText('Showing revision {}. Changes will not be saved.'.format(arg)) self.revisionnotice.show() elif arg == '#': self.terminal.print_('Current revision: {}'.format(jsondata['revision'])) elif not arg: if not self.revisionactive: self.terminal.error('Already showing latest revision') else: currenttab = self.tabbar.currentIndex() self.set_tab_index(currenttab) else: self.terminal.error('Unknown argument: "{}"'.format(arg))
def __init__(self, parent): super().__init__(parent) self.fullscreen = False self.setDisabled(True) hotkeypairs = ( ('home', self.goto_index), ('toggle fullscreen', self.toggle_fullscreen), ('zoom in', self.zoom_in), ('zoom out', self.zoom_out), ('reset zoom', self.zoom_reset) ) self.hotkeys = { key: QtGui.QShortcut(QtGui.QKeySequence(), self, callback) for key, callback in hotkeypairs } self.template = read_file(local_path(join('templates', 'viewer_page_template.html'))) self.css = "" # Is set every time the config is reloaded self.rawtext = "" self.formatconverters = [] self.chapterstrings = [] # Layout layout = QtGui.QVBoxLayout(self) kill_theming(layout) self.webview = QtWebKit.QWebView(self) layout.addWidget(self.webview) layout.setStretchFactor(self.webview, 1) self.webview.settings().setDefaultTextEncoding('utf-8') self.info_panel = InfoPanel(self) layout.addWidget(self.info_panel, 0)
def view_page(self, data): self.setEnabled(True) self.data = data self.info_panel.set_data(data) self.rawtext = format_rawtext(read_file(data.file), self.formatconverters, self.chapterstrings) self.set_html()
def start_logging(self, arg): arg = arg.lower().strip() filepath = self.textarea.file_path if not filepath: self.error('Can\'t log an unnamed file! Save and try again (without offset)') return # Paths logdir, indexpath, relative_filepath = self.get_logpaths() index = get_index(indexpath) if not arg: if relative_filepath in index: self.print_('File is being logged.') else: self.print_('File is not being logged.') return if arg not in ('y','n'): self.error('Argument should be y/n! (use offset/no offset)') return if relative_filepath in index: self.error('File already logged!') return # Offsets if arg == 'y': offset = len(re.findall(r'\S+', read_file(self.textarea.file_path))) else: offset = 0 # Init logfname = generate_logfilename(logdir, relative_filepath) index[relative_filepath] = logfname write_file(join(logdir, logfname), str(offset) + '\n') write_json(indexpath, index) self.print_('Started logging file!')
def save_tab(self): """ Attempt to save the active tab, both the text and the scrollbar/cursor position. Return True if it succeeds, return False if it fails. """ if self.revisionactive: return True currenttab = self.tabbar.currentIndex() if self.textarea.document().isModified(): try: fname = join(self.root, self.tabbar.current_page_fname()) firstline, _ = read_file(fname).split('\n', 1) data = self.textarea.toPlainText() write_file(fname, firstline + '\n' + data) except Exception as e: print(str(e)) self.terminal.error('Something went wrong when saving! (Use q! to force)') return False cursorpos = self.textarea.textCursor().position() scrollpos = self.textarea.verticalScrollBar().sliderPosition() self.tabbar.set_page_position(currenttab, cursorpos, scrollpos) self.textarea.document().setModified(False) return True
def index_stories(path): """ Find all files that match the filter, and return a sorted list of them with wordcount, paths and all data from the metadata file. """ attributes = ( ('title', {'filter': 'text', 'parser': 'text'}), ('tags', {'filter': 'tags', 'parser': 'tags'}), ('description', {'filter': 'text', 'parser': 'text'}), ('wordcount', {'filter': 'number'}), ('current_page', {'filter': 'number', 'parser': 'text'}), ('length', {'filter': 'number', 'parser': 'text'}), ('file', {}), ('lastmodified', {'filter': 'number'}), ('metadatafile', {}), ) metafile = lambda dirpath, fname: join(dirpath, '.'+fname+'.metadata') files = ((read_json(metafile(dirpath, fname)), join(dirpath, fname), metafile(dirpath, fname)) for dirpath, _, filenames in os.walk(path) for fname in filenames if exists(metafile(dirpath, fname))) entries = ((metadata['title'], frozenset(metadata['tags']), metadata['description'], len(re.findall(r'\S+', read_file(fname))), int(metadata['current_page']), int(metadata['length']), fname, os.path.getmtime(fname), metadatafile) for metadata, fname, metadatafile in files) return attributes, entries
def get_anime_images(rootdir): from urllib.request import urlretrieve outdir = local_path('imgcache') rx = r'<a href="http://myanimelist.net/anime/\d+/.+?/pics">\s*<img src="(http://.+?)" alt' for fname in os.listdir(rootdir): rawdata = read_file(os.path.join(rootdir, fname)) imgurl = re.search(rx, rawdata).group(1) urlretrieve(imgurl, os.path.join(outdir, fname + '.jpg'))
def cmd_print_filename(self, arg): fname = self.current_page_path() if arg == 'c': firstline, _ = read_file(fname).split('\n', 1) date = json.loads(firstline)['created'] self.terminal.print_('File created at ' + date) else: self.terminal.print_(self.tabbar.current_page_fname())
def read_config(self): # config configfile = os.path.join(self.configpath, 'kalpana-chapters.conf') make_sure_config_exists(configfile, os.path.join(self.pluginpath, 'default_config.json')) self.sidebar.settings = read_json(configfile) # stylesheet cssfile = os.path.join(self.configpath, 'kalpana-chapters.css') make_sure_config_exists(cssfile, os.path.join(self.pluginpath, 'default_theme.css')) self.sidebar.setStyleSheet(parse_stylesheet(read_file(cssfile)))
def save_pages(path, name, pages): template = read_file(local_path('pagetemplate.html')) for n, page in enumerate(pages): controls = gen_controls(name, n, len(pages)) out = template.format(controls=controls, **page) fpath = os.path.join(path, name) if len(pages) > 1: fpath += ' - Page {:03}'.format(n + 1) fpath += '.html' write_file(fpath, out)
def save_pages(path, name, pages): template = read_file(local_path('pagetemplate.html')) for n, page in enumerate(pages): controls = gen_controls(name, n, len(pages)) out = template.format(controls=controls, **page) fpath = os.path.join(path, name) if len(pages) > 1: fpath += ' - Page {:03}'.format(n+1) fpath += '.html' write_file(fpath, out)
def add_to_recent_files(self, filename): listfname = self.get_path('recentfiles') length = self.get_setting('recent file list length') # This fixes both symlinks and relative paths realfname = os.path.realpath(filename) recentfiles = [realfname] if os.path.exists(listfname): oldrecentfiles = read_file(listfname).splitlines() recentfiles += [x for x in oldrecentfiles if x != realfname][:length-1] write_file(listfname, '\n'.join(recentfiles)) self.update_recent_files.emit()
def reload_settings(self): self.defaultstyle = read_json(local_path('defaultstyle.json')) self.css_template = read_file(local_path(join('templates','template.css'))) self.index_css_template = read_file(local_path(join('templates','index_page.css'))) settings, style, stylepath = read_config(self.configdir, self.defaultstyle) # TODO: FIX THIS UGLY ASS SHIT # Something somewhere f***s up and changes the settings dict, # therefor the deepcopy(). Fix pls. #if settings != self.settings: if settings['title']: self.setWindowTitle(settings['title']) else: self.setWindowTitle('Nomia') self.settings = copy.deepcopy(settings) self.index_viewer.update_settings(settings) self.popuphomekey.setKey(QtGui.QKeySequence(settings['hotkey home'])) #if style != self.style: self.style = style.copy() self.update_style(style) write_json(stylepath, style)
def set_page(self, text: Optional[str] = None, fname: Optional[str] = None, css: Optional[str] = default_css, format: str = 'auto') -> None: assert (text and not fname) or (fname and not text) if not css: css = default_css if not text: text = read_file(fname) page = generate_page(text, fname, css, format) self.setHtml(page)
def on_save(self): logdir, indexpath, relative_filepath = self.get_logpaths() index = get_index(indexpath) # Abort if the current file isn't in the index (= isn't being logged) if relative_filepath not in index: return logfile = join(logdir, index[relative_filepath]) wc = self.textarea.get_wordcount() lastwc = read_file(logfile).splitlines()[-1].split(';',1)[-1] if int(lastwc) == wc: return data = '{};{}\n'.format(datetime.now(), wc) with open(logfile, 'a', encoding='utf-8') as f: f.write(data)
def cmd_rename_current_page(self, title): if not title.strip(): oldtitle = self.tabbar.pages[self.tabbar.currentIndex()][0] self.terminal.prompt('r {}'.format(oldtitle)) return try: self.tabbar.rename_page(title) except KeyError as e: self.terminal.error(e.args[0]) else: fname = self.current_page_path() firstline, data = read_file(fname).split('\n', 1) jsondata = json.loads(firstline) jsondata['title'] = title write_file(fname, json.dumps(jsondata) + '\n' + data)
def __init__(self, configdir): super().__init__() self.paths = get_paths(configdir) for x in ('config_dir', 'plugins', 'spellcheck-pwl'): if not exists(self.paths[x]): os.makedirs(self.paths[x], mode=0o755, exist_ok=True) self.current_style = {} self.css_template = common.read_file(common.local_path('template.css')) self.default_config = get_default_config() self.auto_setting_acronyms = get_auto_setting_acronym(self.default_config) self.setting_types = get_setting_types(self.default_config) self.setting_callbacks = defaultdict(list) self.auto_settings, self.manual_settings = {}, {} self.settings = ChainMap()
def load_tab(self, newtab): """ Load a new tab with the correct data and scrollbar/cursor position. Note that this does not in any way save existing data. """ self.tabbar.setCurrentIndex(newtab) self.update_tabcounter() fname = self.current_page_path() _, data = read_file(fname).split('\n', 1) self.textarea.setPlainText(data) self.textarea.document().setModified(False) # Set the scrollbar/cursor positions cursorpos, scrollpos = self.tabbar.get_page_position(newtab) tc = self.textarea.textCursor() tc.setPosition(min(cursorpos, self.textarea.document().characterCount()-1)) self.textarea.setTextCursor(tc) self.textarea.verticalScrollBar().setSliderPosition(scrollpos)
def get_backstory_data(fname): out = {'wordcount': 0, 'pages': 0} root = fname + '.metadir' if not os.path.isdir(root): return out for dirpath, _, filenames in os.walk(root): for f in filenames: # Skip old revision files if re.search(r'\.rev\d+$', f) is not None: continue try: data = read_file(join(dirpath, f)).split('\n',1)[1] words = len(re.findall(r'\S+', data)) except: # Just ignore the file if something went wrong # TODO: add something here if being verbose? pass else: out['wordcount'] += words out['pages'] += 1 return out
def get_plugins(plugin_root_path, loadorder_path): # Create the loadorder file if it doesn't exist if not os.path.exists(loadorder_path): open(loadorder_path, 'w').close() loadorder = [l for l in common.read_file(loadorder_path).splitlines() if l and not l.startswith('#')] out = [] for plugin_name in loadorder: plugin_path = join(plugin_root_path,plugin_name) if not os.path.exists(plugin_path): print("Plugin directory {} doesn't exist.".format(plugin_name)) continue sys.path.append(plugin_path) try: loaded_plugin = importlib.import_module(plugin_name) except ImportError: print("Plugin {} could not be imported. Most likely because it's " "not a valid plugin.".format(plugin_name)) else: print("Plugin {} loaded.".format(plugin_name)) out.append((plugin_name, plugin_path, loaded_plugin)) return out
def load_pages(self, root): """ Read all pages from the specified directory and build a list of them. """ fnames = os.listdir(root) for f in fnames: if re.search(r'\.rev\d+$', f) is not None: continue if os.path.isdir(join(root, f)): continue firstline, data = read_file(join(root, f)).split('\n', 1) try: jsondata = json.loads(firstline) except ValueError: self.print_('Bad/no properties found on page {}, fixing...'.format(f)) title = fixtitle(f) jsondata = generate_page_metadata(title) write_file(join(root, f), '\n'.join([jsondata, firstline, data])) yield [title, f, 0, 0] else: fixedjsondata = check_and_fix_page_metadata(jsondata, data, join(root, f)) yield [fixedjsondata['title'], f, 0, 0]
def extract_html_data(rootdir): """ Get the relevant data from the files: * Studio(s) * Episode length * Rating """ ratingrx = r'<span.+?>Rating:</span>\s*(\S+?)\s+-\s+.+?\s*</div>' studiorx = r'<span.+?>Studios:</span>\s*<a href="/anime/producer/\d+/.+?" title=".+?">(.+?)</a>' nostudiorx = r'<span.+?>Studios:</span>\s*None found, <a href=".+?">add some</a>' eplengthrx = r'<span.+?>Duration:</span>\s*((?P<hours>\d+)\s+hr\.\s*)?((?P<mins>\d+)\s+min\.\s*)?(per\s+ep\.)?\s*</div>' data = {} for fname in os.listdir(rootdir): rawdata = read_file(os.path.join(rootdir, fname)) try: rating = re.search(ratingrx, rawdata).group(1) except AttributeError: print('rating', fname) return try: studio = re.search(studiorx, rawdata).group(1) except AttributeError: if re.search(nostudiorx, rawdata) is not None: studio = '' else: print('studio', fname) try: raweplength = re.search(eplengthrx, rawdata).groupdict(0) except AttributeError: print('ep length', fname) return eplength = int(raweplength['hours'])*3600 + int(raweplength['mins'])*60 data[fname] = { 'rating': unescape(rating), 'studio': unescape(studio), 'episode_length': eplength } return data
format = 'html' elif ext == '.txt': format = 'rawtext' else: format = fallback else: format = fallback # Check to see if the markdown lib exists if format == 'markdown' and not markdown_available: format = fallback # Check if format is supported at all if format not in formats: format = fallback # Parse the shit if format == 'rawtext': body = html.escape(text).replace('\n', '<br>') return html_boilerplate.format(body='<pre>{}</pre>'.format(body), css=css) elif format == 'markdown': body = markdown.markdown(text) return html_boilerplate.format(body=body, css=css) elif format == 'html': return text if __name__ == '__main__': from libsyntyche.common import write_file fname = '/home/nycz/gitprojects/sapfo/README.md' text = read_file(fname) page = generate_page(text, fname, '', 'auto') write_file('/home/nycz/gitprojects/libsyntyche/test.html', page)
def __init__(self, textarea, local_path): super().__init__() self.html = read_file(os.path.join(local_path, 'sidebar.html')) self.setStyleSheet("Sidebar {border: 0px; border-left: 2px solid #111}") self.setReadOnly(True) self.hide()
def update_recent_files(self): listfname = self.get_path('recentfiles') if not os.path.exists(listfname): return self.recent_files = read_file(listfname).splitlines() self.recent_files_index = 0