class Gallery: def __init__(self, config, root_path): self.config = config self.root_path = root_path self.source_image_path = os.path.join(root_path, "source_images") self.source_video_path = os.path.join(root_path, "source_videos") self.theme_name = config.get("gallery", "theme") self.themes_path = os.path.join(root_path, "themes") self.theme_path = os.path.join(self.themes_path, self.theme_name) if not os.path.exists(self.theme_path): raise Exception("theme '%s' not found " % self.theme_name) themeconfigpath = os.path.join(self.theme_path, "config.txt") if not os.path.exists(themeconfigpath): raise Exception("couldn't find theme config.txt") self.config.read(themeconfigpath) self.templates_path = os.path.join(self.theme_path, "templates") self.template_path = os.path.join(root_path, "templates") self.output_path = os.path.join(root_path, "output") self.small_size = self.config.get("gallery", "small_image_size").split(",") self.large_size = self.config.get("gallery", "large_image_size").split(",") self.video_size = self.config.get("gallery", "video_max_size").split(",") self.configure_templates() self.discover_plugins() def discover_plugins(self): self.plugin_manager = PluginManager() self.plugin_manager.discover_plugins( os.path.join(self.root_path, "plugins")) def configure_templates(self): self.tempEnv = Environment( loader=FileSystemLoader(self.templates_path)) def get_template(self, templateName): return self.tempEnv.get_template(templateName) def generate(self): images = self.discover_images() videos = self.process_videos() print videos images = self.generate_images(images) # plugin call point - pre page generation, with images as # arguments (to provide extra context for pages) extra_context = self.plugin_manager.prePageGeneration( self.config, self.source_image_path, self.source_video_path, images, videos) self.generate_pages(images, videos, extra_context) self.copy_static_content() def upload(self): # plugin call point, generation complete - upload self.plugin_manager.upload(self.config, self.output_path) # plugin call point, generation complete - notify self.plugin_manager.notify(self.config, self.output_path) def copy_static_content(self): static_path = os.path.join(self.theme_path, "static") static_output_path = os.path.join(self.output_path, "static") if os.path.exists(static_output_path): shutil.rmtree(static_output_path) shutil.copytree(static_path, static_output_path) def discover_images(self): images = [] for filename in os.listdir(self.source_image_path): if filename.lower().find(".jpg") != -1: image = MediaObject( source_path=os.path.join( self.source_image_path, filename), filename=filename, output_path=self.output_path) image.target_small_size = self.small_size image.target_large_size = self.large_size images.append(image) print "%s images found" % len(images) return images def process_videos(self): videos = [] vp = videoprocessing.VideoProcessor() for filename in os.listdir(self.source_video_path): video = MediaObject(type=MediaObject.TYPE_VIDEO, filename=filename, source_path=os.path.join( self.source_video_path, filename), output_path=self.output_path) videos.append(video) if video.transcoded: # copy already transcoded video target_path = os.path.join(self.output_path, video.filename) print "copying m4v video: %s" % video.source_path shutil.copy(video.source_path, target_path) else: # transcode the others target_filename = video.filename[ :video.filename.find(".")] + ".m4v" video.filename = target_filename target_path = os.path.join(self.output_path, target_filename) print "transcoding %s to %s" % (video.source_path, target_path) params = vp.getSizeAndDuration(video.source_path) vp.trancodeRawVideo( video.source_path, target_path, params, self.video_size) video.thumb_path = vp.getScreencap( video.source_path, self.output_path) video.thumb_filename = os.path.split(video.thumb_path)[1] # get dimensions and duration params = vp.getSizeAndDuration( os.path.join(self.output_path, video.filename)) video.width = params.get('width', None) video.height = params.get('height', None) video.hours = params.get('hours', None) video.minutes = params.get('minutes', None) video.seconds = params.get('seconds', None) video.title = filename return videos def generate_pages(self, images, videos, extra_context): try: themeMode = self.config.get("theme", "THEME_MODE") except ConfigParser.NoOptionError: themeMode = 'static' # merge video and photo records media = [] media.extend(videos) media.extend(images) for mediaobject in media: if mediaobject.type == MediaObject.TYPE_PHOTO: mediaobject.page = "view_photo_%s.html" % mediaobject.id elif mediaobject.type == MediaObject.TYPE_VIDEO: mediaobject.page = "view_video_%s.html" % mediaobject.id if themeMode == 'ajax': return self.generate_ajax_pages(media, extra_context) elif themeMode == 'static': return self.generate_plain_pages(media, extra_context) else: raise Exception("unknown mode in theme") def generate_ajax_pages(self, media, extra_context): page_context = { 'root_url': self.config.get("gallery", "ROOT_URL"), 'imagecount': len(media), 'media': media, 'gallerytitle': self.config.get("gallery", "title"), } page_context.update(extra_context) self.render_page("index.html", "index.html", page_context) # create video embed pages for mediaitem in media: if mediaitem.type == MediaObject.TYPE_VIDEO: local_page_context = { 'video': mediaitem, 'root_url': self.config.get("gallery", "ROOT_URL"), } self.render_page("embedvideo.html", "embed_%s.html" % mediaitem.filename, local_page_context) self.render_static_pages(page_context) def generate_plain_pages(self, media, extra_context): indexIsAlbumPage = self.config.getboolean( "theme", "INDEX_IS_ALBUM_PAGE") imagesPerPage = int(self.config.get("theme", "IMAGES_PER_PAGE")) # set up previous and next links for i in range(len(media)): prevlink = None nextlink = None if i > 0: prevlink = media[i - 1].page if i < (len(media) - 1): nextlink = media[i + 1].page media[i].next_link = nextlink media[i].prev_link = prevlink pages = int(math.ceil((len(media) / float(imagesPerPage)))) page_context = { 'root_url': self.config.get("gallery", "ROOT_URL"), 'images_per_page': imagesPerPage, 'pages': pages, 'imagecount': len(media), 'gallerytitle': self.config.get("gallery", "title"), } page_context.update(extra_context) pagelinks = [] for page in range(pages): if page == 0 and indexIsAlbumPage: pagelinks.append( {'title': (int(page) + 1), 'link': "index.html"}) else: pagelinks.append( {'title': (int(page) + 1), 'link': "page%s.html" % (int(page) + 1)}) page_context['pagelinks'] = pagelinks # generate album pages if indexIsAlbumPage: currPageName = "index.html" else: currPageName = "page1.html" for page in range(pages): pageno = page + 1 print "generating page %s" % pageno page_media = media[page * imagesPerPage:pageno * imagesPerPage] # set the owner page for the media items for mediaitem in page_media: mediaitem.home_page = currPageName page_context['media'] = page_media page_context['pageno'] = pageno prevlink = None if page > 0: prevlink = "page%s.html" % page nextlink = None if pageno < pages: nextlink = "page%s.html" % (int(pageno) + 1) page_context['prevlink'] = prevlink page_context['nextlink'] = nextlink self.render_page("albumpage.html", currPageName, page_context) currPageName = "page%s.html" % (pageno + 1) # generate image and video view pages for mediaitem in media: if mediaitem.type == MediaObject.TYPE_PHOTO: local_page_context = { 'img': mediaitem, 'root_url': self.config.get("gallery", "ROOT_URL"), } self.render_page( "viewimage.html", mediaitem.page, local_page_context) if mediaitem.type == MediaObject.TYPE_VIDEO: local_page_context = { 'video': mediaitem, 'root_url': self.config.get("gallery", "ROOT_URL"), } self.render_page( "viewvideo.html", mediaitem.page, local_page_context) self.render_static_pages(page_context) def render_static_pages(self, context): indexIsAlbumPage = self.config.getboolean( "theme", "INDEX_IS_ALBUM_PAGE") if not indexIsAlbumPage: self.render_page("index.html", "index.html", context) # render any other template not in the list of reserved names for template in self.tempEnv.list_templates(): if template not in RESERVED_TEMPLATES: print "rendering static page - %s" % template self.render_page(template, template, context) def render_page(self, templateName, outputName, context): page_template = self.get_template(templateName) html = page_template.render(context) outfile = open(os.path.join(self.output_path, outputName), "w") outfile.write(html) outfile.close() def generate_images(self, images): p = Pool() images = p.map(process_image, [[image] for image in images]) print images return images
class NomnsParse(QApplication): """Application Control.""" def __init__(self, *args): super().__init__(*args) # Plugin support self.plugins = PluginManager(self) self.plugins.discover_plugins(enable_all=config.data['general']['enable_plugins']) # End plugin support # Updates self._toggled = False self._log_reader = None # Load Parsers self._load_parsers() self._settings = SettingsWindow() # Tray Icon self._system_tray = QSystemTrayIcon() self._system_tray.setIcon(QIcon(resource_path('data/ui/icon.png'))) self._system_tray.setToolTip("nParse") # self._system_tray.setContextMenu(self._create_menu()) self._system_tray.activated.connect(self._menu) self._system_tray.show() # Turn On self._toggle() if self.new_version_available(): self._system_tray.showMessage( "nParse Update".format(ONLINE_VERSION), "New version available!\ncurrent: {}\nonline: {}".format( CURRENT_VERSION, ONLINE_VERSION ), msecs=3000 ) self.plugins.hook(Plugin.on_app_start, self) def _load_parsers(self): self._parsers = [ parsers.Maps(), parsers.Spells() ] for parser in self._parsers: self.plugins.hook(Plugin.on_parser_load, parser) if parser.name in config.data.keys() and 'geometry' in config.data[parser.name].keys(): g = config.data[parser.name]['geometry'] parser.setGeometry(g[0], g[1], g[2], g[3]) if config.data[parser.name]['toggled']: parser.toggle() def _toggle(self): if not self._toggled: try: config.verify_paths() except ValueError as error: self._system_tray.showMessage( error.args[0], error.args[1], msecs=3000) else: self._log_reader = logreader.LogReader( config.data['general']['eq_log_dir']) self._log_reader.new_line.connect(self._parse) self._toggled = True else: if self._log_reader: self._log_reader.deleteLater() self._log_reader = None self._toggled = False def _parse(self, new_line): if new_line: timestamp, text, charname = new_line # (datetime, text) # don't send parse to non toggled items, except maps. always parse maps for parser in [parser for parser in self._parsers if config.data[parser.name]['toggled'] or parser.name == 'maps']: parser.parse(timestamp, text, charname) def _menu(self, event): """Returns a new QMenu for system tray.""" menu = QMenu() menu.setAttribute(Qt.WA_DeleteOnClose) # check online for new version new_version_text = "" if self.new_version_available(): new_version_text = "Update Available {}".format(ONLINE_VERSION) else: new_version_text = "Version {}".format(CURRENT_VERSION) check_version_action = menu.addAction(new_version_text) menu.addSeparator() get_eq_dir_action = menu.addAction('Select EQ Logs Directory') menu.addSeparator() parser_toggles = set() for parser in self._parsers: toggle = menu.addAction(parser.name.title()) toggle.setCheckable(True) toggle.setChecked(config.data[parser.name]['toggled']) parser_toggles.add(toggle) menu.addSeparator() settings_action = menu.addAction('Settings') # Plugin support for adding menu items if self.plugins.has_plugins(): menu.addSeparator() plugin_options = self.plugins.prepare_plugin_menu(menu) self.plugins.hook(Plugin.on_menu_display, menu) # End plugin support menu.addSeparator() quit_action = menu.addAction('Quit') # Show the menu action = menu.exec_(QCursor.pos()) # Plugin support for handling menu actions if plugin_options: plugin_options(action) self.plugins.hook(Plugin.on_menu_click, action) # End plugin support if action == check_version_action: webbrowser.open('https://github.com/nomns/nparse/releases') elif action == get_eq_dir_action: dir_path = str(QFileDialog.getExistingDirectory( None, 'Select Everquest Logs Directory')) if dir_path: config.data['general']['eq_log_dir'] = dir_path config.save() self._toggle() elif action == settings_action: if self._settings.exec_(): # Update required settings for parser in self._parsers: if parser.windowOpacity() != config.data['general']['parser_opacity']: parser.setWindowOpacity( config.data['general']['parser_opacity'] / 100) parser.settings_updated() # some settings are saved within other settings automatically # force update for parser in self._parsers: if parser.name == "spells": parser.load_custom_timers() elif action == quit_action: if self._toggled: self._toggle() # save parser geometry for parser in self._parsers: g = parser.geometry() config.data[parser.name]['geometry'] = [ g.x(), g.y(), g.width(), g.height() ] config.save() self._system_tray.setVisible(False) # Plugin support self.plugins.hook(Plugin.on_app_quit, self) self.quit() elif action in parser_toggles: parser = [ parser for parser in self._parsers if parser.name == action.text().lower()][0] parser.toggle() def new_version_available(self): # this will only work if numbers go up try: for (o, c) in zip(ONLINE_VERSION.split('.'), CURRENT_VERSION.split('.')): if int(o) > int(c): return True except: return False