Skip to content
This repository has been archived by the owner on Jul 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #32 from hughrun/setuptools
Browse files Browse the repository at this point in the history
Use setuptools to enable install and uninstall from pip
  • Loading branch information
hughrun authored Nov 21, 2019
2 parents 0b1305c + d3fa2f2 commit 93ddc35
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 103 deletions.
10 changes: 7 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
settings.py
schedule.sh
week.plist
day.plist

# Setuptools distribution folder.
/dist/

# Python egg metadata, regenerated from source files by setuptools.
/*.egg-info
/*.egg
55 changes: 28 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,49 @@
# pocket-snack
# pocketsnack

When your Pocket list is overwhelming, pocket-snack lets you see just what you can read today

This is the version 2 README. If you haven't yet upgraded you can still use the [version 1 README](v1_README.md).
This is the version 2 documentation. If you haven't yet upgraded you can still use the [version 1 README](v1_README.md).

## A note on version 2

All commands have changed since version 1 - read the _Usage_ section carefully. This was necessary in order to provide better functionality without making the code too confusing.

One of the changes is that the `refresh` command from version 1 no longer exists. This is so that `--since`, and `--before` can be used with both `--stash` and `lucky_dip`. If you want replicate `refresh` you simply need to run `--stash` followed by `--lucky_dip`. From the command line you could do:

```bash
pocketsnack -s && pocketsnack -d
```

The automation of `pocketsnack refresh` has _also_ been removed. This didn't really work very consistently, and was causing a lot of maintenance headaches. I'm looking at how to bring it back in a different way, but for now it's been removed.

## Getting started

### Quick version

1. make sure you have installed Python 3 and it is callable with `python3`
2. copy `settings-example.py` to `settings.py`
3. create Pocket app and paste consumer key into `settings.py`
4. run `bash install.sh` and follow the prompts
1. make sure you have installed Python 3
2. download `pocketsnack` using git or the download link in [releases](releases)
3. move into the top `pocketsnack` directory
4. `pip3 install .` or if pip points to Python3, `pip install .`
5. Edit `settings/settings.py`

### Dependencies
### Installing Python 3

You will need Python 3.x installed and it must be called by `python3`, rather than `python`. These instructions, and the install script, assume you are using a Unix-like (Linux, BSD, MacOS) operating system. Microsoft Windows is not currently supported.

On MacOS the easiest thing to do is to [install Python 3 using Homebrew](https://docs.brew.sh/Homebrew-and-Python): `brew install python`.

The install script should install the `requests` module for you when you run `bash install.sh`. If you prefer, you can install it manually using **pip**: `pip3 install requests`
You will need Python 3.x installed. On MacOS the easiest thing to do is to [install Python 3 using Homebrew](https://docs.brew.sh/Homebrew-and-Python): `brew install python`.

### Settings

You will need to copy **settings-example.py** to a new file called **settings.py** before you start. You can do this however you like, but from the command line you could use `cp settings-example.py settings.py`, and then edit it with a text editor like `nano`.
You will need to copy `settings/settings-example.py` to a new file - `settings/settings.py` before you start. You can do this however you like, but from the command line you could use `cp settings/settings-example.py settings/settings.py`, and then edit it with a text editor like `nano` or VS Code, but any text editor will do the job.

You can adjust most settings, but the defaults in **settings-example.py** should be ok for most users. Check the comments in **settings.example.py** for an explanation of each setting.
You can adjust most settings, but the defaults in `settings-example.py` should be ok for most users. Check the comments in `settings.example.py` for an explanation of each setting.

### Creating a Pocket consumer key for your app

1. Log in to Pocket in a web browser
2. Go to https://getpocket.com/developer and click 'CREATE NEW APP'
3. Complete the form: you will need all permissions, and the platform should be 'Desktop (other)'
4. Your new app will show a 'consumer key', which you need to paste into the first line in settings.py
2. Go to `https://getpocket.com/developer` and click 'CREATE NEW APP'
3. Complete the form: you will need all permissions, and the platform should be _Desktop (other)_
4. Your new app will show a **consumer key**, which you need to paste into the first line in `settings.py`

### Pocket access token
### Authorising your app with a Pocket access token

Pocket uses OAuth to confirm that your app has permission from your user account to do stuff in your account. This means you need to authorise the app before you can do anything else. Once you have copied you app consumer key into settings.py, when you run the `install.sh` bash script, this will run `authorise` for you. If you prefer to install manually, or want to change the Pocket account details, you should run `pocketsnack --authorise` to get your token (see below).
Pocket uses OAuth to confirm that your app has permission from your user account to do stuff in your account. This means you need to authorise the app before you can do anything else. Once you have copied your app consumer key into settings.py, run `pocketsnack --authorise` to get your token.

You should now have a line at the bottom of settings.py saying something like `pocket_access_token = 'aa11bb-zz9900xx'`

Expand All @@ -67,7 +65,7 @@ Outputs the first article returned by a call to the API. Normally you will never

This command has an 's', not a 'z', and the short version is a 'u', not an 'a'.

You need this to authorise your app. This command is automatically run by `install.sh`. Everything else works exclusively on the command line, but _authorise_ needs to open a browser to complete the authorisation process, so you need to run this on a machine with a web browser. It will authorise your app with your user, wait for you to confirm that you have completed the authorisation (by typing 'done') and then add the token to `settings.py`. Use it if you want to change the Pocket account you are using with pocketsnack.
You need this to authorise your app. Everything else works exclusively on the command line, but _authorise_ needs to open a browser to complete the authorisation process, so you need to run this on a machine with a web browser. It will authorise your app with your user, wait for you to confirm that you have completed the authorisation (by typing 'done') and then add the token to `settings.py`. You also need to run `--authorise` if you want to change the Pocket account you are using with `pocketsnack`.

## action commands

Expand Down Expand Up @@ -137,14 +135,17 @@ Run lucky_dip but only choose from items last updated longer ago than one week:

## Uninstalling or moving to a new directory

Don't like _pocket-snack_ any more or want to re-install it in a new directory? No problem, you will just need to do a little maintenance:
### If you installed with pip

Just run `pip uninstall pocketsnack` or `pip3 uninstall pocketsnack`.

1. Delete the executable link - if you don't do this when re-installing in a different directory, running `pocketsnack` will fail because it will still be pointing at the old directory.
### If you installed using the legacy install.sh script

`rm /usr/local/bin/pocketsnack`
1. Delete the executable link: `rm /usr/local/bin/pocketsnack`

2. Now you can safely delete the pocket-snack directory.
If you don't do this when re-installing in a different directory, running `pocketsnack` will fail because it will still be pointing at the old directory.
2. Now you can safely delete the pocket-snack directory: `rm -r pocketsnack`

## Bugs and suggestions

Please log an issue - but check the existing issues first in case it's already been/being dealt with.
Please log an issue - but check the existing issues first in case it's already been/being dealt with.
26 changes: 13 additions & 13 deletions main.py → bin/pocketsnack
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import subprocess

# local modules
import settings
import pocket_toolkit as pt
from settings import settings
from lib import toolkit as pt

# ----------------
# Settings
Expand Down Expand Up @@ -129,7 +129,7 @@
print(auth)

elif options.lucky_dip:
print('\033[0;36mRunning lucky dip...\033[0;m')
print('\033[0;36m Running lucky dip...\033[0;m')
dip = pt.lucky_dip(consumer_key, settings.pocket_access_token, settings.archive_tag, settings.items_per_cycle, settings.num_videos, settings.num_images, settings.num_longreads, settings.longreads_wordcount, options.before, options.since)
print('\033[0;36m' + dip + '\033[0;m')

Expand All @@ -149,23 +149,23 @@ def print_info(response, collection):
longreads += 1

if options.before:
print(collection + 'has ' + items + ' items ' + 'updated prior to ' + str(options.before) + ' days ago and ' + str(longreads) + ' are longreads.')
print(collection + 'has ' + items + ' items ' + 'updated prior to ' + str(options.before) + ' days ago and ' + str(longreads) + ' are longreads.\033[0;m')
elif options.since:
print(collection + 'has ' + items + ' items ' + 'updated since ' + str(options.since) + ' days ago and ' + str(longreads) + ' are longreads.')
print(collection + 'has ' + items + ' items ' + 'updated since ' + str(options.since) + ' days ago and ' + str(longreads) + ' are longreads.\033[0;m')
else:
print(collection + 'has ' + items + ' items and ' + str(longreads) + ' are longreads.')
print(collection + 'has ' + items + ' items and ' + str(longreads) + ' are longreads.\033[0;m')

if options.archive:
response = pt.info(consumer_key, settings.pocket_access_token, archive_tag, options.before, options.since)
if len(response) > 0:
print_info(response, 'The TBR archive ')
print_info(response, '\033[0;36m The TBR archive ')
else:
print('No items match that query')
print('\033[0;36m No items match that query\033[0;m')

elif options.list:
response = pt.info(consumer_key, settings.pocket_access_token, False, options.before, options.since)
if len(response) > 0:
print_info(response, 'The user List ')
print_info(response, '\033[0;36m The user List ')
else:
print('No items match that query')

Expand All @@ -175,17 +175,17 @@ def print_info(response, collection):
elif options.purge:

if options.list:
print('\033[0;36mPurging tags in the list\033[0;m')
print('\033[0;36m Purging tags in the list\033[0;m')
purge = pt.purge_tags('unread', settings.retain_tags, archive_tag, consumer_key, settings.pocket_access_token, options.before, options.since)
print(purge)

elif options.archive:
print('\033[0;36mPurging tags in the archive\033[0;m')
print('\033[0;36m Purging tags in the archive\033[0;m')
purge = pt.purge_tags('archive', settings.retain_tags, archive_tag, consumer_key, settings.pocket_access_token, options.before, options.since)
print(purge)

elif options.all:
print('\033[0;36mPurging tags in both the archive and the list\033[0;m')
print('\033[0;36m Purging tags in both the archive and the list\033[0;m')
purge = pt.purge_tags('all', settings.retain_tags, archive_tag, consumer_key, settings.pocket_access_token, options.before, options.since)
print(purge)

Expand All @@ -204,4 +204,4 @@ def print_info(response, collection):
print('\n That command cannot be used by itself. Check \033[0;36mpocketsnack --help\033[0;m for more information\n')

else:
print('\033[0;36mpocketsnack\033[0;m requires commands and/or flags to do anything useful. Try \033[0;36mpocketsnack -h\033[0;m for more information')
print('\033[0;36m pocketsnack\033[0;m requires commands and/or flags to do anything useful. Try \033[0;36mpocketsnack -h\033[0;m for more information')
37 changes: 0 additions & 37 deletions install.sh

This file was deleted.

Empty file added lib/__init__.py
Empty file.
41 changes: 19 additions & 22 deletions pocket_toolkit.py → lib/toolkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@
import urllib
import webbrowser

# local modules
import settings

# ----------------
# Create app
# ----------------
Expand All @@ -52,7 +49,6 @@
# reusable functions
# -----------------

# (TODO: make this a proper class object)
# Pocket expects particular HTTP headers to send and receive JSON
headers = {"Content-Type": "application/json; charset=UTF-8", "X-Accept": "application/json"}

Expand Down Expand Up @@ -136,7 +132,7 @@ def authorise(consumer_key, redirect_uri): # With an 's'. Deal with it.
# get the JSON response and save the token to a param for the next step
request_token = requestOne.json()['code']
# print the request token to the console so you know it happened
print('\033[0;36mYour request token (code) is \033[0;m' + request_token)
print('\033[0;36m Your request token (code) is \033[0;m' + request_token)

# now you need to authorise the app in your Pocket account
# build the url
Expand All @@ -147,7 +143,7 @@ def authorise(consumer_key, redirect_uri): # With an 's'. Deal with it.
# We're not writing a server app here so we use a little hack to check whether the user has finished authorising before we continue
# Just wait for the user (you!) to indicate they have finished authorising the app
# the '\n' prints a new line
print('\033[0;36mAuthorise your app in the browser tab that just opened.\033[0;m')
print('\033[0;36m Authorise your app in the browser tab that just opened.\033[0;m')
user_input = input('Type "done" when you have finished authorising the app in Pocket \n>>')

if user_input == "done":
Expand All @@ -158,16 +154,17 @@ def authorise(consumer_key, redirect_uri): # With an 's'. Deal with it.
# get the JSON response as a Python dictionary and call it 'res'.
res = requestTwo.json()
# Finally we have the access token!
print('\033[0;36mAccess token for ' + res['username'] + ' is \033[0;m' + res['access_token'])
print('\033[0;36m Access token for ' + res['username'] + ' is \033[0;m' + res['access_token'])
# Assign the access token to a parameter called access_token
access_token = res['access_token']
# replace the pocket_access_token line rather than just adding an extra at the end
settings_file = fileinput.FileInput("settings.py", inplace=True)
# TODO: change this file path
settings_file = fileinput.FileInput("pocketsnack/settings.py", inplace=True)
repl = "pocket_access_token = " + "'" + access_token + "'"
for line in settings_file:
line = re.sub('(pocket_access_token)+.*', repl, line)
print(line.rstrip())
return '\033[0;36mToken added to settings.py - you are ready to use pocketsnack.\033[0;m'
return '\033[0;36m Token added to settings.py - you are ready to use pocketsnack!\033[0;m 🎉'

# ------------------------------
# Read info about Pocket account
Expand Down Expand Up @@ -357,7 +354,7 @@ def readd(selection):
for v in chosen.values():
tot_added += v
remaining = available - tot_added
completed_message = 'Success! ' + str(tot_added) + ' items added to your reading list, including '
completed_message = ' \033[0;36mSuccess! ' + str(tot_added) + ' items added to your reading list, including '
if random_choice:
completed_message += str(chosen['random']) + ' random articles, '
if tot_images:
Expand All @@ -372,19 +369,19 @@ def readd(selection):
caveat = 'last updated earlier than ' + str(before) + ' days ago '
if since:
caveat = 'last updated more recently than ' + str(since) + ' days ago '
completed_message += 'with ' + str(remaining) + ' other items ' + caveat + 'remaining to be read.'
completed_message += 'with ' + str(remaining) + ' other items ' + caveat + 'remaining to be read.\033[0;m'
return completed_message
# else if there's nothing tagged with the archive_tag
else:
return 'Nothing to be read!'
return '\033[0;36m Nothing to be read!\033[0;m'
else:
if attempts < 4:
attempts += 1
time.sleep(10)
print('\033[0;36mAttempting to connect...\033[0;m')
print('\033[0;36m Attempting to connect...\033[0;m')
return run_lucky_dip(attempts)
else:
msg = "\033[0;36mSorry, no connection after 4 attempts.\033[0;m"
msg = "\033[0;36m Sorry, no connection after 4 attempts.\033[0;m"
return msg

return run_lucky_dip(0)
Expand Down Expand Up @@ -428,10 +425,10 @@ def purge_tags(state, retain_tags, archive_tag, consumer_key, pocket_access_toke
actions.append(update)

process_items(actions, consumer_key, pocket_access_token)
return '\033[1;36mUndesirable elements have been purged.\033[1;m'
return '\033[1;36m Undesirable elements have been purged.\033[1;m'

else:
return '\033[0;36mNo items from which to purge tags.\033[0;m'
return '\033[0;36m No items from which to purge tags.\033[0;m'

"""
Stash
Expand All @@ -452,12 +449,12 @@ def purge_tags(state, retain_tags, archive_tag, consumer_key, pocket_access_toke
# -----------------

def stash(consumer_key, pocket_access_token, archive_tag, replace_all_tags, retain_tags, favorite, ignore_tags, before, since):
print('\033[0;36mStashing items...\033[0;m')
print('\033[0;36m Stashing items...\033[0;m')
# if ignore_faves is set to True, don't get favorite items
params = {"consumer_key": consumer_key, "access_token": pocket_access_token, "detailType": "complete", "state": "unread"}
if favorite:
params['favorite'] = "0"
print('\033[0;36mSkipping favorited items...\033[0;m')
print('\033[0;36m Skipping favorited items...\033[0;m')

def run_stash(attempts):
if connection_live() == True:
Expand Down Expand Up @@ -509,22 +506,22 @@ def run_stash(attempts):
item_action = {"item_id": item, "action": "archive"}
archive_actions.append(item_action)

print('\033[0;36mArchiving ' + str(len(archive_actions)) + ' items...\033[0;m')
print('\033[0;36m Archiving ' + str(len(archive_actions)) + ' items...\033[0;m')

# archive items
process_items(archive_actions, consumer_key, pocket_access_token)

# return a list of what was stashed and, if relevant, what wasn't
skipped_items = len(item_list) - len(items_to_stash)
return str(len(items_to_stash)) + ' items archived with "' + archive_tag + '" and ' + str(skipped_items) + ' items skipped due to retain tag.'
return ' ' + str(len(items_to_stash)) + ' items archived with "' + archive_tag + '" and ' + str(skipped_items) + ' items skipped due to retain tag.'
else:
if attempts < 4:
attempts += 1
time.sleep(10)
print('\033[0;36mAttempting to connect...\033[0;m')
print('\033[0;36m Attempting to connect...\033[0;m')
return run_stash(attempts)
else:
msg = "\033[0;31mSorry, no connection after 4 attempts.\033[0;m"
msg = "\033[0;31m Sorry, no connection after 4 attempts.\033[0;m"
return msg

return run_stash(0)
Expand Down
Empty file added settings/__init__.py
Empty file.
Loading

0 comments on commit 93ddc35

Please sign in to comment.