예제 #1
0
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
예제 #2
0
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
예제 #3
0
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
예제 #4
0
    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:
    """
예제 #9
0
#!/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}')
예제 #10
0
    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:
예제 #11
0
#!/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)
예제 #12
0
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)
예제 #14
0
        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)
예제 #15
0
#!/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'
        )
예제 #16
0
    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)
예제 #17
0
def get_template_tag() -> str:
    tt = Tools.getEnv('template_tag')
    if '#' not in tt or tt == str():
        tt = '#Template'
    return tt
예제 #18
0
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
예제 #19
0
    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')
예제 #20
0
#!/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",
예제 #21
0
#!/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,
예제 #22
0
#!/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)",
예제 #23
0
        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:
예제 #25
0
#!/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
예제 #27
0
#!/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',
예제 #28
0
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"
예제 #29
0
#!/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()
예제 #30
0
#!/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)