Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

executable file 198 lines (153 sloc) 5.494 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
#!/usr/bin/env python

import argparse
import codecs
from datetime import datetime
import errno
import json
import os
import sys

CONFIG_DIR = os.path.expanduser('~/.ff')
SESSIONS_DIR = os.path.join(CONFIG_DIR, 'sessions')
DATE_FORMAT = "%Y%m%d%H%M"


class AttrDict(dict):
    def __getattr__(self, name):
        if name.startswith('_') or name == 'trait_names':
            raise AttributeError
        return self[name]


class Session(object):
    def __init__(self, data):
        self.data = data

    def itertabs(self):
        for window in self.data.windows:
            for tab in window.tabs:
                yield tab

    @property
    def tabs(self):
        return list(self.itertabs())


def format_date(timestamp=None):
    if timestamp:
        dt = datetime.fromtimestamp(float(timestamp))
    else:
        dt = datetime.now()
    return dt.strftime(DATE_FORMAT)


def make_dir(path):
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno == errno.EEXIST:
            pass


def itersessions(include_saved=False):
    if sys.platform == 'darwin':
        path = os.path.expanduser('~/Library/Application Support/Firefox/Profiles')
    else:
        path = os.path.expanduser('~/.mozilla/firefox')
    for profile in (x for x in os.listdir(path) if x.endswith('.default')):
        yield os.path.join(path, profile, 'sessionstore.js')
    if include_saved:
        for session in os.listdir(SESSIONS_DIR):
            yield os.path.join(SESSIONS_DIR, session)

def load_session(session=None):
    if session and not os.path.exists(os.path.expanduser(session)):
        for s in itersessions(include_saved=True):
            if session in s:
                session = s
    elif not session:
        session = next(itersessions())

    with open(session) as f:
        return Session(json.load(f, object_hook=AttrDict))


def save_session():
    import shutil
    session = next(itersessions())
    shutil.copy(session, os.path.join(SESSIONS_DIR, format_date() + '.js'))


def replace_session(new_session):
    import shutil
    session = next(itersessions())
    shutil.copy(new_session, session)


def list_tabs(args):
    if args.all:
        sessions = (load_session(s) for s in itersessions(include_saved=True))
    else:
        sessions = [args.session]
    for session in sessions:
        for s_idx, tab in enumerate(session.tabs):
            for t_idx, entry in enumerate(tab.entries):
                try:
                    print ':'.join(str(x) for x in [s_idx, t_idx]), entry.title, '-', entry.url
                except KeyError:
                    pass


def list_sessions():
    for session in itersessions(include_saved=True):
        print session


# commands
def list_command(args):
    if args.sessions:
        list_sessions()
    else:
        list_tabs(args)


def read_command(args):
    try:
        s_idx, t_idx = (int(x) for x in args.idx.split(':'))
        url = args.session.tabs[s_idx].entries[t_idx].url
    except:
        print 'Invalid index'
        return

    import requests
    from readability.readability import Document
    import html2text
    h = html2text.HTML2Text()
    h.inline_links = False
    h.ignore_images = True
    h.ignore_emphasis = True
    res = requests.get(url)
    if res.ok:
        article = Document(res.content)
        print article.short_title()
        print h.handle(article.summary())
    else:
        print res.headers['status']


def open_command(args):
    import webbrowser
    try:
        s_idx, t_idx = (int(x) for x in args.idx.split(':'))
        url = args.session.tabs[s_idx].entries[t_idx].url
    except:
        print 'Invalid index'
        return
    webbrowser.open(url)


def save_command(args):
    save_session()


def clear_command(args):
    os.remove(args.session)


if __name__ == '__main__':
    # make sure config dir exists
    if not os.path.exists(SESSIONS_DIR):
        make_dir(SESSIONS_DIR)

    sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
    parser = argparse.ArgumentParser()
    parser.add_argument('--session', action='store', help='session to operate on')
    subparsers = parser.add_subparsers()

    # list command
    list_parser = subparsers.add_parser('list', help='List sessions or tabs')
    list_parser.add_argument('--tabs', action='store_true', help='List open tabs')
    list_parser.add_argument('--sessions', action='store_true', help='List sessions')
    list_parser.add_argument('--all', action='store_true', help='List tabs from all sessions')
    list_parser.set_defaults(command=list_command)

    # save command
    save_parser = subparsers.add_parser('save', help='Save current session')
    save_parser.set_defaults(command=save_command)

    # clear command
    clear_parser = subparsers.add_parser('clear', help='Clear current session')
    clear_parser.set_defaults(command=clear_command)

    # read command
    read_parser = subparsers.add_parser('read', help='Read idx')
    read_parser.add_argument('idx', action='store', help='Index of article to read')
    read_parser.set_defaults(command=read_command)

    # open command
    open_parser = subparsers.add_parser('open', help='Open idx')
    open_parser.add_argument('idx', action='store', help='Index of article to open in Firefox')
    open_parser.set_defaults(command=open_command)

    if sys.argv[1:]:
        args = parser.parse_args()
        args.session = load_session(args.session)
        command = args.command
        command(args)
Something went wrong with that request. Please try again.