def get_cache_directory() -> str: """Get Alfreds Cache Directory, if not existent the directory will be created Returns: str: Cache Directory """ target_dir = Tools.getEnv('alfred_workflow_cache') if not (os.path.isdir(target_dir)): os.mkdir(target_dir) return target_dir
def history_paths() -> list: """ Get valid pathes to history from HISTORIES variable Returns: list: available paths of history files """ user_dir = os.path.expanduser("~") hists = [f"{user_dir}{h}" for h in HISTORIES] valid_hists = list() for h in hists: if "Firefox" in h: h = path_to_fire_history(h) if os.path.isfile(h): valid_hists.append(h) Tools.log(f"{h} → found") else: Tools.log(f"{h} → NOT found") return valid_hists
def rmDir(path: str, ignore_errors: bool = True) -> bool: """ Remove directory and it's content Args: path (string): path to specific markdown notes ignore_errors (bool, optional): Ignore errors. Defaults to True. Returns: bool: True in case removal was successful otherwise False """ if os.path.exists(path): shutil.rmtree(path, ignore_errors) Tools.log(f"DELETED DIR: {path}") return not (os.path.exists(path)) else: return False
def getFilenameFormat(self): """ Get fileformat from WF env Returns: str: fileformat or fallback """ frmt_env = Tools.getEnv('filename_format') if frmt_env is None or frmt_env.strip() == "": frmt_env = '{title}' return frmt_env
def path_to_fire_history(f_home: str) -> str: """ Get valid pathes to firefox history Returns: str: available paths of history file """ valid_hist = "" if os.path.isdir(f_home): f_home_dirs = [f"{f_home}/{o}" for o in os.listdir(f_home)] for f in f_home_dirs: if os.path.isdir(f) and f.endswith("default-release"): f_sub_dirs = [f"{f}/{o}" for o in os.listdir(f)] for fs in f_sub_dirs: if os.path.isfile(fs) and os.path.basename( fs) == "places.sqlite": valid_hist = fs break else: Tools.log(f"{f_home} → NOT found") return valid_hist
def sql(db: str) -> list: """ Executes SQL for Firefox and Chrome depending on History path provided in db: str Args: db (str): Path to History file Returns: list: result list of dictionaries (Url, Title, VisiCount) """ res = [] history_db = f"/tmp/{uuid.uuid1()}" try: shutil.copy2(db, history_db) with sqlite3.connect(history_db) as c: cursor = c.cursor() if "Firefox" in db: # SQL for Firefox Browser select_statement = f""" select DISTINCT url, title, visit_count FROM moz_places JOIN moz_historyvisits WHERE title != '' order by last_visit_date DESC LIMIT {SQL_FIRE_LIMIT}; """ else: # SQL for Chromium Browsers select_statement = f""" SELECT DISTINCT urls.url, urls.title, urls.visit_count FROM urls, visits WHERE urls.id = visits.url AND urls.title IS NOT NULL AND urls.title != '' order by last_visit_time DESC; """ Tools.log(select_statement) cursor.execute(select_statement) r = cursor.fetchall() res.extend(r) os.remove(history_db) # Delete History file in /tmp except sqlite3.Error as e: Tools.log(f"SQL Error{e}") sys.exit(1) return res
def get_histories(dbs: list, query: str) -> list: """ Load History files into list Args: dbs(list): list with valid history paths Returns: list: filters hitory entries """ results = list() with Pool(len(dbs)) as p: # Exec in ThreadPool results = p.map(sql, [db for db in dbs]) matches = [] for r in results: matches = matches + r results = search_in_tuples(matches, query) results = removeDuplicates(results) # Remove duplicate Entries results = results[:30] # Search entered into Alfred results = Tools.sortListTuple(results, 2) # Sort based on visits return results
"brave": "/Library/Application Support/BraveSoftware/Brave-Browser/Default/History", "brave_dev": "/Library/Application Support/BraveSoftware/Brave-Browser-Dev/Default/History", "chromium": "/Library/Application Support/Chromium/Default/History", "chrome": "/Library/Application Support/Google/Chrome/Default/History", "firefox": "/Library/Application Support/Firefox/Profiles", "opera": "/Library/Application Support/com.operasoftware.Opera/History", "sidekick": '/Library/Application Support/Sidekick/Default/History', "vivaldi": "/Library/Application Support/Vivaldi/Default/History" } HISTORIES = list() # Get Browser Histories to load per env (true/false) for k in HISTORY_MAP.keys(): is_set = Tools.getEnvBool(k) if is_set: HISTORIES.append(HISTORY_MAP.get(k)) # Limit SQL results for better performance # will only be applied to Firefox history SQL_FIRE_LIMIT = Tools.getEnv("sql_fire_limitx", default=500) Tools.log("PYTHON VERSION:", sys.version) if sys.version_info < (3, 7): print("Python version 3.7.0 or higher required!") sys.exit(0) def history_paths() -> list: """
#!/usr/bin/python3 import os from Alfred3 import Tools # automatic blueutil installer os.environ['PATH'] = os.popen('./_sharedresources "blueutil"').readline() query = Tools.getArgv(1) adr, switch = tuple(query.split(";")) if switch == "disconnected": Tools.log(adr) os.popen(f'blueutil --connect {adr}') else: os.popen(f'blueutil --disconnect {adr}')
Args: key (str): key of key-value pair value (str): value of key-value pair """ config = Plist() config.setVariable(key, value) value = '<EMPTY>' if value == str() else value wf.setItem(title="Proceed?", subtitle=f'{key} will be changed to: {value}', arg='') wf.setIcon('icons/hand.png', 'image') wf.addItem() query = Tools.getArgv(1) action_key_value = Tools.getEnv('action_key_value') [action, key, value] = action_key_value.split('|') if action_key_value != str() else [ str(), str(), str() ] wf_dir = os.getcwd() query = Tools.getArgv(1) wf = Items() if action == str(): print_config(query) elif action == 'selection': get_selection(key, query) else:
#!/usr/bin/python3 import os import sys from Alfred3 import Tools from MyNotes import Search f_path = Tools.getArgv(1) # Path to MD Note s = Search() url_scheme_path = s.getUrlScheme(f_path) filename = os.path.basename(f_path) md_link = f"[{filename}]({url_scheme_path})" sys.stdout.write(md_link)
from MyNotes import NewNote, Search from QuerySplitter import QuerySplitter def get_mdfiles_list_content() -> str: """ Get markdown links in unordered markdown list Returns: str: Markdown unordered list """ ns = Search() output = list() files = os.getenv('files').split( '|') # one or list of md file paths from prev wf step for f in files: link_title = ns.getNoteTitle(f) file_name = os.path.basename(f) output.append(f'* [{link_title}]({pathname2url(file_name)})') return ("\n".join(output)) query = Tools.getArgv(1) # Title of the Note qs = QuerySplitter(query) MyNote = NewNote(qs.title, tags=qs.tags, content=get_mdfiles_list_content()) md_path = MyNote.createNote() sys.stdout.write(md_path)
#!/usr/bin/python3 # -*- coding: utf-8 -*- import os import sys from Alfred3 import Tools from MyNotes import NewNote from QuerySplitter import QuerySplitter query = Tools.getArgv(1) # Note title, can contain Tags → #TAG template = Tools.getEnv('template_path') # Read template path from previous wf step in case template ws choosen if query.isspace(): # if query contains a SPACE aka nothing was entered today = NewNote.getTodayDate(fmt='%d-%m-%Y %H-%M-%S') query = f"My Note {today}" qs = QuerySplitter(query) if query: Note = NewNote(qs.title, template_path=template, tags=qs.tags) fPath = Note.createNote() sys.stdout.write(fPath)
os.remove(cache_file_path) content_list = [f"### MD Notes with tag: {tag}"] for el in md_notes_list: content_list.append( f"* [{el['title']}]({el['path']}) `{el['filename']}`") content = "\n".join(content_list) with open(cache_file_path, "w") as f: f.write(content) return cache_file_path # create MD search object md_search = Search() # Load Env variables query = Tools.getArgv(1) if len(Tools.getArgv(1)) > 2 else "" if query is not "" and not (query.startswith("#")): query = f"#{query}" # Get Search config with AND and OR search_terms, search_type = md_search.get_search_config(query) # create WF object wf = Items() # exec search if search terms were entered if len(search_terms) > 0: sorted_file_list = md_search.notes_search(search_terms, search_type) matches = len(sorted_file_list) file_pathes = [f['path'] for f in sorted_file_list] arg_string = "|".join(file_pathes)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from urllib.request import pathname2url import MyNotes from Alfred3 import Items as Items from Alfred3 import Keys as K from Alfred3 import Tools as Tools # create MD search object md_search = MyNotes.Search() # Load environment variables ext = md_search.getNotesExtension() query = Tools.getArgv(1) # Search term todos = md_search.todoSearch(query) wf = Items() if len(todos) > 0: for i in todos: md_path = pathname2url(i['path']) md_title = i['title'] if i['title'] != str() else Tools.chop(i['filename'], ext) wf.setItem( title=i['todo'], subtitle=f"{K.ARROW_RIGHT} {md_title} (Created: {Tools.getDateStr(i['ctime'])}, Modified: {Tools.getDateStr(i['mtime'])})", arg=i['path'], valid=True, type='file' )
to_replace = ['/', '\\', ':', '|'] tmp = f.strip() for i in to_replace: tmp = tmp.replace(i, '-') return tmp def writeMarkdown(md_content, md_path): with open(md_path, "w+") as f: f.write(md_content) mn = Search() ext = mn.getNotesExtension() p = mn.getNotesPath() argv = Tools.getArgv(1) url = argv if argv.startswith('http://') or argv.startswith( 'https://') else str() # TODO: When HTML is not fetchable, the URL will be used. # Fix formatting from <url> to markdown url [title](url) if url: Tools.notify('Fetch URL...', 'The Note will be opened after the import...') markdown = Markdown(url) today = markdown.getTodayDate(fmt="%d.%m.%Y") today_time = markdown.getTodayDate(fmt="%d-%m-%Y %H-%M") md = markdown.getMarkdownContent() file_name = parseFilename(markdown.getTitle()) if file_name == str(): file_name = Tools.strJoin('WebClip from ', today_time)
def get_template_tag() -> str: tt = Tools.getEnv('template_tag') if '#' not in tt or tt == str(): tt = '#Template' return tt
def get_template_tag() -> str: tt = Tools.getEnv('template_tag') if '#' not in tt or tt == str(): tt = '#Template' return tt SUFFIX = " (DEFAULT)" # create MD search object my_notes = MyNotes.Search() # Load env variables ext = my_notes.getNotesExtension() query = Tools.getArgv(1) default_template = Tools.getEnv('default_template') template_tag = get_template_tag() # Get Files sorted in Notes directory all_files = my_notes.getFilesListSorted() template_files = sorted(all_files, key=lambda x: x['filename'] != default_template) wf = Items() for md_file in template_files: if my_notes.isNoteTagged(md_file['path'], template_tag) and query in md_file['filename']: suffix = str() if md_file['filename'] == default_template: suffix = SUFFIX
Returns: str: Target file path for quicklookurl """ target_dir = get_cache_directory() spath = os.path.normpath(wf_dir).split(os.sep) wf_dir_name = ''.join( [i for i in spath if str(i).startswith('user.workflow')]) if wf_dir_name != str(): target_file = f"{target_dir}/{wf_dir_name}.md" with open(target_file, "wb+") as f: f.write(content) return target_file Tools.logPyVersion() Workflows = Workflows() query = Tools.getArgv(1) matches = Workflows.get_workflows() if query == str( ) else Workflows.search_in_workflows(query) clean_cache() alf = Items() if len(matches) > 0: for m in matches: # init Keyword and Keyboard text formatter for markdown output kf = KeywordFormatter() # WF description description = m.get('description') if m.get('description') else ' - ' # WF name name = m.get('name')
#!/usr/bin/python3 # -*- coding: utf-8 -*- import os from urllib.request import pathname2url from Alfred3 import Items, Tools from MyNotes import Search # Get NotePath as path_query env variable note_path = Tools.getEnv("path_query1") # Get query used in search markdown notes as path_query env variable query = Tools.getEnv("path_query2") md_notes = Search() # Get NoteTitle for specific note note_title = md_notes.getNoteTitle(note_path) file_name = pathname2url(os.path.basename(note_path)) # If query in notes search was empty subtitle uses following string back_query = "<EMPTY>" if not query else query # Actions in ScriptFilter menu data ACTIONS = [ { "title": "Back", "subtitle": f"Back to Search with query: {back_query}", "arg": f"back|{query}", "icon": "icons/back.png", "visible": True }, { "title": "Markdown Link",
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from Alfred3 import Items as Items from Alfred3 import Keys as K from Alfred3 import Tools as Tools from MyNotes import Search # create MD search object md = Search() # Get environment variables ext = md.getNotesExtension() query = Tools.getArgv(1) # Tag name if query is str(): # Tag Search and sort based on tag name tag_results = md.tagSearch(query, 'tag', reverse=False) else: # Tag Search and sort based on number of Hits tag_results = md.tagSearch(query, 'count', reverse=True) wf = Items() if bool(tag_results): for tag, counter in tag_results.items(): wf.setItem( title=f'{tag}', subtitle= f"{counter} Hit(s), ({K.CMD} to paste tag into frontmost app)", valid=True,
#!/usr/bin/python3 # -*- coding: utf-8 -*- from unicodedata import normalize from Alfred3 import Items as Items from Alfred3 import Keys as K from Alfred3 import Tools as Tools from MyNotes import Search # create MD search object md = Search() # Get environment variables ext = md.getNotesExtension() query = normalize('NFC', Tools.getArgv(1)) # Tag name if query is str(): # Tag Search and sort based on tag name tag_results = md.tagSearch(query, 'tag', reverse=False) else: # Tag Search and sort based on number of Hits tag_results = md.tagSearch(query, 'count', reverse=True) wf = Items() if bool(tag_results): for tag, counter in tag_results.items(): wf.setItem( title=f'{tag}', subtitle=f"{counter} Hit(s), ({K.CMD} to paste tag into frontmost app)",
vpn_tpl = (v, status) target.append(vpn_tpl) return target def arrange(lst: list, toarrange: str) -> list: for i in lst: if i[1] == toarrange: lst.remove(i) lst.insert(0, i) return lst wf = Items() query = Tools.getArgv(1) connected_vpn = get_vpn(status=VPN.CONNECTED) disconnected_vpn = get_vpn(status=VPN.DISCONNECTED) vpn = list() vpn = add_to_vpnlist(connected_vpn, vpn, VPN.CONNECTED) vpn = add_to_vpnlist(disconnected_vpn, vpn, VPN.DISCONNECTED) if len(vpn) > 0: vpn = arrange(vpn, VPN.CONNECTED) for v in vpn: if query.lower() in v[0].lower() or query == "": arg = f"connect" if v[1] == VPN.DISCONNECTED else f"disconnect" wf.setItem(title=f"{v[0]}", subtitle=f"{v[1].upper()}, Press \u23CE to {arg}",
#!/usr/bin/python3 # -*- coding: utf-8 -*- from unicodedata import normalize from Alfred3 import Items as Items from Alfred3 import Keys as K from Alfred3 import Tools as Tools from MyNotes import Search CMD = u'\u2318' SHIFT = u'\u21E7' # create MD search object md_search = Search() query = normalize('NFC', Tools.getArgv(1)) # Get Search config with AND and OR search_terms, search_type = md_search.get_search_config(query) # create WF object wf = Items() # exec search if search terms were entered if len(search_terms) > 0: sorted_file_list = md_search.notes_search(search_terms, search_type) # get full list of file in case no search was entered else: sorted_file_list = md_search.getFilesListSorted() # Write search results into WF object for f in sorted_file_list:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from Alfred3 import Items as Items from Alfred3 import Keys as K from Alfred3 import Tools as Tools from MyNotes import Search CMD = u'\u2318' SHIFT = u'\u21E7' # create MD search object md_search = Search() query = Tools.getArgv(1) # Search Term(s) # Get Search config with AND and OR search_terms, search_type = md_search.get_search_config(query) # create WF object wf = Items() # exec search if search terms were entered if len(search_terms) > 0: sorted_file_list = md_search.notes_search(search_terms, search_type) # get full list of file in case no search was entered else: sorted_file_list = md_search.getFilesListSorted() # Write search results into WF object for f in sorted_file_list: c_date = Tools.getDateStr(f['ctime'])
'/Library/Application Support/BraveSoftware/Brave-Browser/Default/Bookmarks', "brave_dev": '/Library/Application Support/BraveSoftware/Brave-Browser-Dev/Default/Bookmarks', "chrome": '/Library/Application Support/Google/Chrome/Default/Bookmarks', "chromium": '/Library/Application Support/Chromium/Default/Bookmarks', "firefox": '/Library/Application Support/Firefox/Profiles', "opera": '/Library/Application Support/com.operasoftware.Opera/Bookmarks', "sidekick": '/Library/Application Support/Sidekick/Default/Bookmarks', "vivaldi": '/Library/Application Support/Vivaldi/Default/Bookmarks' } FIRE_BOOKMARKS = str() BOOKMARKS = list() # Get Browser Histories to load per env for k in BOOKMARS_MAP.keys(): is_set = Tools.getEnvBool(k) if k == "firefox" and is_set: FIRE_BOOKMARKS = BOOKMARS_MAP.get(k) elif is_set: BOOKMARKS.append(BOOKMARS_MAP.get(k)) def removeDuplicates(li: list) -> list: """ Removes Duplicates from bookmark file Args: li(list): list of bookmark entries Returns: list: filtered bookmark entries
#!/usr/bin/python3 # -*- coding: utf-8 -*- from Alfred3 import Items, Tools from MyNotes import Search query = Tools.getArgv(1) bmt = Tools.getEnv('bookmark_tag') bookmark_tag = bmt if bmt.startswith('#') else f'#{bmt}' search_terms = f'{bookmark_tag}&{query}' if query else bookmark_tag notes = Search() search_terms, _ = notes.get_search_config(search_terms) matches = notes.url_search(search_terms) alf = Items() if matches: for m in matches: note_title = m.get('title') note_path = m.get('path') links = m.get('links') for l in links: url_title = l.get('url_title') url = l.get('url') subtitle = f'NOTE: {note_title} URL: {url[:30]}...' alf.setItem(title=url_title, subtitle=subtitle, arg=url, quicklookurl=url) alf.addMod('cmd',
for query in files_to_delete: file_path, last_query = getFileQuery(query) if os.path.isfile(file_path) and file_path.endswith(ext): file_name = os.path.basename(file_path) # Search for links to other assets and delete each file parent = mn.getNotesPath() assetfile_links = getAssetsLinks(parent, file_path) is_assetfile_deleted = False for l in assetfile_links: # Avoid Markdown file removal if not(l.endswith(ext)): is_assetfile_deleted = rmFile(l) # Delete Assets Folder remove_ext = len(ext) assets_path = Tools.strJoin(file_path[:-remove_ext], ".assets") assets_path_legacy = Tools.strJoin(file_path[:-remove_ext]) is_asset_deleted = rmDir(assets_path) or rmDir(assets_path_legacy) or is_assetfile_deleted # Finally delete the MD File is_file_deleted = rmFile(file_path) # Create Notification Message if len(files_to_delete) == 1: return_text = '- MD Note DELETED'if is_file_deleted else "Cannot delete file: {0}".format( file_name) return_text += '\n- Assets DELETED' if is_asset_deleted else str() if len(files_to_delete) > 1: return_text = f"{len(files_to_delete)} Notes and coresponding Assets deleted"
#!/usr/bin/python3 import os from Alfred3 import Items, Tools # Script Filter icon [Title,Subtitle,arg/uid/icon] wf_items = [ ['Open Workflow', 'Open Workflow in Alfred Preferences', 'open'], ['Path to Clipboard', 'Copy Workflow path to Clipoard', 'clipboard'], ['Open in Terminal', 'Open Workflow path in Terminal', 'terminal'], ['Finder', 'Reveal in Finder', 'finder'], ] # Add file manager defined in Alfred wf env file_manager_path = Tools.getEnv('file_manager') if file_manager_path and os.path.isfile(file_manager_path): app_name = os.path.splitext(os.path.basename(file_manager_path))[0] wf_items.append([app_name, f"Reveal in {app_name}", "file_manager"]) wf = Items() for w in wf_items: wf.setItem(title=w[0], subtitle=w[1], arg=w[2]) icon_path = f'icons/{w[2]}.png' wf.setIcon(icon_path, m_type='image') wf.addItem() wf.write()
#!/usr/bin/python3 import sys from subprocess import PIPE, Popen from Alfred3 import Tools note = Tools.getArgv(1) target_folder = Tools.getEnv("target_folder") scpt = f""" tell application "SideNotes" set n to make new note at folder "{target_folder}" set text of n to "{note}" end tell """ p = Popen(['osascript', '-'], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True) stdout, stderr = p.communicate(scpt) sys.stdout.write(stderr)