diff --git a/.gitignore b/.gitignore index 7a03a2a..150ae18 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,4 @@ .pytest_cache/ build/ dist/ -venv/ -setup.py \ No newline at end of file +venv/ \ No newline at end of file diff --git a/.pylintrc b/.pylintrc index d31bb65..9e75026 100644 --- a/.pylintrc +++ b/.pylintrc @@ -61,7 +61,6 @@ disable= protected-access, too-few-public-methods, - [LOGGING] # Logging modules to check that the string format arguments are in logging diff --git a/.travis.yml b/.travis.yml index 6d0e99c..a82a9bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ python: - "3.4" - "3.5" - "3.6" - - "3.7-dev" + # - "3.7-dev" install: - pip install tox-travis script: diff --git a/README.rst b/README.rst index 485beef..d793292 100644 --- a/README.rst +++ b/README.rst @@ -6,12 +6,51 @@ RFD CLI Installation: +============= + +.. code-block:: pip install rfd Usage +===== - rfd threads 9 --count 10 +.. code-block:: -.. image:: images/rfd_threads_9.png + rfd threads 9 [--count 5] + + +.. image:: https://user-images.githubusercontent.com/4519234/37319853-3a03fb9c-2647-11e8-806e-17156541cf43.png + + +Examples: +========= + + +tail a post: +--------------- + +.. code-block:: + + + ▶ rfd posts https://forums.redflagdeals.com/koodo-targeted-public-mobile-12-120-koodo-6gb-40-no-referrals-2176935/ --tail 4 + + -------------------------------------------------------------------------- + - [0] For those worried about credit ratings, according to Boworell, my credit score rose by 44 points since last month. I did absolutely nothing except open 3 Koodo lines all with medium tabs and I paid off 1 in full the very next day (Shaner) + + -------------------------------------------------------------------------- + - [0] If we want to keep our PM plan but use the code to set up a spouse on the plan is that still okay? + I've read that the port can only be used once now, but does it matter which phone number is ported in? (kid_icarus) + + -------------------------------------------------------------------------- + - [0] blackboxvr6 wrote: ↑Mar 12th, 2018 2:13 pm + Legit 1st line on Wednesday, no shipping email yet... + + + Tuesday before noon and still waiting. (gardener28) + + -------------------------------------------------------------------------- + - [0] Ordered a SIM last Wednesday, haven't heard a peep from Koodo since the initial order confirmation e-mail. (DaJinx) + + -------------------------------------------------------------------------- \ No newline at end of file diff --git a/images/rfd_threads_9.png b/images/rfd_threads_9.png index 5a3cb09..78a96e1 100644 Binary files a/images/rfd_threads_9.png and b/images/rfd_threads_9.png differ diff --git a/rfd/api.py b/rfd/api.py index c70d757..6ee63ce 100644 --- a/rfd/api.py +++ b/rfd/api.py @@ -67,7 +67,16 @@ def get_threads(forum_id, limit): return threads[:limit] -def get_posts(post, limit=5): +def get_posts(post, count=5, tail=False, per_page=40): + """Retrieve posts from a thread. + + Args: + post (str): either post id or full url + count (int, optional): Description + + Yields: + list(dict): body, score, and user + """ if is_valid_url(post): post_id = extract_post_id(post) elif is_int(post): @@ -75,28 +84,62 @@ def get_posts(post, limit=5): else: raise ValueError() - if limit == 0: - response = requests.get( - "https://forums.redflagdeals.com/api/topics/{}/posts?per_page=40&page=1".format(post_id)) - pages = response.json().get('pager').get('total_pages') - elif limit > 40: - pages = ceil(limit / 40) + response = requests.get( + "https://forums.redflagdeals.com/api/topics/{}/posts?per_page=40&page=1".format(post_id)) + total_posts = response.json().get('pager').get('total') + total_pages = response.json().get('pager').get('total_pages') + + if count == 0: + pages = total_pages + if count > per_page: + if count > total_posts: + count = total_posts + pages = ceil(count / per_page) else: - pages = 1 + if tail: + pages = total_pages + else: + pages = 1 + + if tail: + start_page = ceil((total_posts + 1 - count) / per_page) + start_post = (total_posts + 1 - count) % per_page + if start_post == 0: + start_post = per_page + else: + start_page, start_post = 0, 0 # Go through as many pages as necessary - for page in range(pages): - page = page + 1 # page 0 causes issues + for page in range(start_page, pages + 1): response = requests.get( "https://forums.redflagdeals.com/api/topics/{}/posts?per_page={}&page={}".format(post_id, get_safe_per_page( - limit), + per_page), page)) users = users_to_dict(response.json().get('users')) - for _post in response.json().get('posts'): + + _posts = response.json().get('posts') + + # Determine which post to start with (for --tail) + if page == start_page and not start_post == 0: + if tail: + _posts = _posts[start_post - 1:] + else: + _posts = _posts[:start_post] + + for _post in _posts: + count -= 1 + if count < 0: + return + # Sometimes votes is null + if _post.get('votes') is not None: + calculated_score = get_vote_score(_post.get('votes').get( + 'total_up'), _post.get('votes').get('total_down')) + else: + calculated_score = 0 yield{ 'body': strip_html(_post.get('body')), - 'score': get_vote_score(_post.get('votes').get('total_up'), _post.get('votes').get('total_down')), + 'score': calculated_score, 'user': users[_post.get('author_id')], } diff --git a/rfd/rfd_cli.py b/rfd/rfd_cli.py index 760d8b8..e021b2e 100644 --- a/rfd/rfd_cli.py +++ b/rfd/rfd_cli.py @@ -28,9 +28,10 @@ def cli(): @cli.command(short_help="Displays posts in a specific thread.") -@click.option('--count', default=5, help='Number of topics. 0 for all topics') +@click.option('--head', default=0, help='Number of topics. Default is 0, for all topics') +@click.option('--tail', default=0, help='Number of topics. Default is disabled. This will override head.') @click.argument('post_id') -def posts(count, post_id): +def posts(post_id, head, tail): """Displays posts in a specific thread. post_id can be a full url or post id only @@ -41,13 +42,23 @@ def posts(count, post_id): url: https://forums.redflagdeals.com/koodo-targeted-public-mobile-12-120-koodo-5gb-40-no-referrals-2173603 post_id: 2173603 """ - if count < 0: - click.echo("Invalid count.") + if head < 0: + click.echo("Invalid head.") sys.exit(1) + if tail < 0: + click.echo("Invalid tail.") + sys.exit(1) + + # Tail overrides head + if tail > 0: + count = tail + else: + count = head + try: click.echo("-" * get_terminal_width()) - for post in get_posts(post_id, count): + for post in get_posts(post=post_id, count=count, tail=tail > 0): click.echo(" -" + get_vote_color(post.get('score')) + Fore.RESET + post.get('body') + Fore.YELLOW + " ({})".format(post.get('user'))) click.echo(Style.RESET_ALL) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..93c213a --- /dev/null +++ b/setup.py @@ -0,0 +1,36 @@ +import io # for python2 +from os import path +from setuptools import setup + + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the relevant file +with io.open(path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +setup( + name='rfd', + version='0.0.5', + packages=['rfd'], + keywords='cli redflagdeals', + install_requires=[ + 'PyYAML>=3.11', + 'beautifulsoup4>=4.6.0', + 'click>=6.7', + 'colorama>=0.3.9', + 'pytest>=3.4.2', + 'requests>=2.18.4' + ], + url='https://github.com/davegallant/rfd_cli', + license='Apache License, Version 2.0', + author='Dave Gallant', + author_email='davegallant@gmail.com', + description='CLI for RedFlagDeals.com', + long_description=long_description, + entry_points={ + 'console_scripts': [ + 'rfd = rfd.rfd_cli:cli', + ], + }, +) diff --git a/tox.ini b/tox.ini index 597ac0b..c6102fc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,10 @@ [tox] -envlist = py{27,34,35,36,37} +envlist = py{27, + 34, + 35, + 36, + #37, + } [testenv] commands =