1 Commits

Author SHA1 Message Date
Dave Gallant
1531d4e900 Bump version to 0.8.1 2022-05-15 13:19:04 -04:00
12 changed files with 485 additions and 547 deletions

View File

@@ -4,8 +4,5 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: weekly interval: weekly
time: "8:00"
- package-ecosystem: github-actions open-pull-requests-limit: 10
directory: "/"
schedule:
interval: weekly

View File

@@ -6,5 +6,5 @@ jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- uses: psf/black@stable - uses: psf/black@stable

View File

@@ -13,7 +13,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
fetch-depth: 2 fetch-depth: 2
@@ -21,7 +21,7 @@ jobs:
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' }}
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v1
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v1

View File

@@ -7,9 +7,9 @@ jobs:
if: startsWith(github.ref, 'refs/tags') if: startsWith(github.ref, 'refs/tags')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@master
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v1
with: with:
python-version: 3.9 python-version: 3.9
- name: Install pypa/build - name: Install pypa/build

View File

@@ -16,10 +16,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5 uses: actions/setup-python@v1
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}

View File

@@ -12,9 +12,8 @@
- [View Hot Deals](#view-hot-deals) - [View Hot Deals](#view-hot-deals)
- [View and Sort Hot Deals](#view-and-sort-hot-deals) - [View and Sort Hot Deals](#view-and-sort-hot-deals)
- [Search](#search) - [Search](#search)
- [Regex](#regex) - [Advanced](#advanced)
- [View Posts](#view-posts) - [View Posts](#view-posts)
- [JSON Output](#json-output)
- [Shell Completion](#shell-completion) - [Shell Completion](#shell-completion)
- [bash](#bash) - [bash](#bash)
- [zsh](#zsh) - [zsh](#zsh)
@@ -48,6 +47,7 @@ If you have [brew](https://brew.sh):
brew install davegallant/public/rfd brew install davegallant/public/rfd
``` ```
## Usage ## Usage
All commands open up in a [terminal pager](https://en.wikipedia.org/wiki/Terminal_pager). All commands open up in a [terminal pager](https://en.wikipedia.org/wiki/Terminal_pager).
@@ -93,7 +93,7 @@ rfd threads --sort-by views --pages 10
rfd search 'pizza' rfd search 'pizza'
``` ```
#### Regex #### Advanced
Regular expressions can be used for search. Regular expressions can be used for search.
@@ -111,16 +111,6 @@ rfd posts https://forums.redflagdeals.com/kobo-vs-kindle-2396227/
This allows for easy grepping and searching for desired expressions. This allows for easy grepping and searching for desired expressions.
### JSON Output
All commands support JSON output.
For example:
```sh
rfd threads --output json
```
## Shell Completion ## Shell Completion
Shell completion can be enabled if using `bash` or `zsh`. Shell completion can be enabled if using `bash` or `zsh`.

864
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "rfd" name = "rfd"
version = "0.9.0" version = "0.8.1"
description = "view RedFlagDeals.com from the command line" description = "view RedFlagDeals.com from the command line"
authors = ["Dave Gallant <davegallant@gmail.com>"] authors = ["Dave Gallant <davegallant@gmail.com>"]
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
@@ -15,10 +15,10 @@ requests = ">=2.22.0"
soupsieve = "<3.0" soupsieve = "<3.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pre-commit = "2.1.1" pre-commit = "1.21.0"
pylint = "^2.12.0" pylint = "^2.12.0"
pytest = ">=4.6.6" pytest = ">=4.6.6"
rope = "1.1.1" rope = "1.0.0"
[tool.poetry.scripts] [tool.poetry.scripts]
rfd = "rfd.__main__:cli" rfd = "rfd.__main__:cli"

View File

@@ -65,7 +65,7 @@ def get_posts(post):
Args: Args:
post (str): either full url or postid post (str): either full url or postid
Returns: Yields:
list(Post): Posts list(Post): Posts
""" """
if is_valid_url(post): if is_valid_url(post):
@@ -81,28 +81,22 @@ def get_posts(post):
total_pages = response.json().get("pager").get("total_pages") total_pages = response.json().get("pager").get("total_pages")
posts = []
for page in range(0, total_pages + 1): for page in range(0, total_pages + 1):
response = requests.get( response = requests.get(
f"{API_BASE_URL}/api/topics/{post_id}/posts?per_page=40&page={page}" f"{API_BASE_URL}/api/topics/{post_id}/posts?per_page=40&page={page}"
) )
users = create_user_map(response.json().get("users")) users = create_user_map(response.json().get("users"))
current_posts = response.json().get("posts") posts = response.json().get("posts")
for _post in current_posts: for i in posts:
# Sometimes votes is null # Sometimes votes is null
if _post.get("votes") is not None: if i.get("votes") is not None:
calculated_score = calculate_score(_post) calculated_score = calculate_score(i)
else: else:
calculated_score = 0 calculated_score = 0
posts.append( yield Post(
Post( body=strip_html(i.get("body")),
body=strip_html(_post.get("body")), score=calculated_score,
score=calculated_score, user=users[i.get("author_id")],
user=users[_post.get("author_id")],
)
) )
return posts

View File

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
import logging import logging
import sys import sys
import json
import click import click
try: try:
@@ -12,14 +11,8 @@ except ImportError: # for Python<3.8
import importlib_metadata as metadata import importlib_metadata as metadata
from colorama import init from colorama import init
from .api import get_threads, get_posts from .api import get_threads, get_posts
from .threads import ( from .threads import parse_threads, search_threads, sort_threads, generate_thread_output
parse_threads, from .posts import generate_posts_output
search_threads,
sort_threads,
generate_thread_output,
ThreadEncoder,
)
from .posts import generate_posts_output, PostEncoder
init() init()
@@ -58,10 +51,7 @@ def cli(ctx):
@cli.command(short_help="Display all posts in a thread.") @cli.command(short_help="Display all posts in a thread.")
@click.argument("post_id") @click.argument("post_id")
@click.option( def posts(post_id):
"--output", default=None, help="Defaults to custom formatting. Other options: json"
)
def posts(post_id, output):
"""Iterate all pages and display all posts in a thread. """Iterate all pages and display all posts in a thread.
post_id can be a full url or post id only post_id can be a full url or post id only
@@ -73,23 +63,12 @@ def posts(post_id, output):
""" """
try: try:
if output == "json": click.echo_via_pager(generate_posts_output(get_posts(post=post_id)))
click.echo_via_pager(
json.dumps(
get_posts(post=post_id),
cls=PostEncoder,
indent=2,
sort_keys=True,
)
)
else:
click.echo_via_pager(generate_posts_output(get_posts(post=post_id)))
except ValueError: except ValueError:
click.echo("Invalid post id.") click.echo("Invalid post id.")
sys.exit(1) sys.exit(1)
except AttributeError as err: except AttributeError:
click.echo("The RFD API did not return the expected data. %s", err) click.echo("The RFD API did not return the expected data.")
sys.exit(1) sys.exit(1)
@@ -97,10 +76,7 @@ def posts(post_id, output):
@click.option("--forum-id", default=9, help="The forum id number") @click.option("--forum-id", default=9, help="The forum id number")
@click.option("--pages", default=1, help="Number of pages to show. Defaults to 1.") @click.option("--pages", default=1, help="Number of pages to show. Defaults to 1.")
@click.option("--sort-by", default=None, help="Sort threads by") @click.option("--sort-by", default=None, help="Sort threads by")
@click.option( def threads(forum_id, pages, sort_by):
"--output", default=None, help="Defaults to custom formatting. Other options: json"
)
def threads(forum_id, pages, sort_by, output):
"""Display threads in the specified forum id. Defaults to 9 (hot deals). """Display threads in the specified forum id. Defaults to 9 (hot deals).
Popular forum ids: Popular forum ids:
@@ -120,18 +96,7 @@ def threads(forum_id, pages, sort_by, output):
_threads = sort_threads( _threads = sort_threads(
parse_threads(get_threads(forum_id, pages)), sort_by=sort_by parse_threads(get_threads(forum_id, pages)), sort_by=sort_by
) )
if output == "json": click.echo_via_pager(generate_thread_output(_threads))
click.echo_via_pager(
json.dumps(
sort_threads(_threads, sort_by=sort_by),
cls=ThreadEncoder,
indent=2,
sort_keys=True,
)
)
else:
click.echo_via_pager(generate_thread_output(_threads))
@cli.command(short_help="Search deals based on a regular expression.") @cli.command(short_help="Search deals based on a regular expression.")
@@ -140,11 +105,8 @@ def threads(forum_id, pages, sort_by, output):
"--forum-id", default=9, help="The forum id number. Defaults to 9 (hot deals)." "--forum-id", default=9, help="The forum id number. Defaults to 9 (hot deals)."
) )
@click.option("--sort-by", default=None, help="Sort threads by") @click.option("--sort-by", default=None, help="Sort threads by")
@click.option(
"--output", default=None, help="Defaults to custom formatting. Other options: json"
)
@click.argument("regex") @click.argument("regex")
def search(pages, forum_id, sort_by, output, regex): def search(pages, forum_id, sort_by, regex):
"""Search deals based on regex. """Search deals based on regex.
Popular forum ids: Popular forum ids:
@@ -167,17 +129,6 @@ def search(pages, forum_id, sort_by, output, regex):
_threads = parse_threads(get_threads(forum_id, pages=pages)) _threads = parse_threads(get_threads(forum_id, pages=pages))
for thread in search_threads(threads=_threads, regex=regex): for thread in search_threads(threads=_threads, regex=regex):
matched_threads.append(thread) matched_threads.append(thread)
click.echo_via_pager(
if output == "json": generate_thread_output(sort_threads(matched_threads, sort_by=sort_by))
click.echo_via_pager( )
json.dumps(
sort_threads(matched_threads, sort_by=sort_by),
indent=2,
sort_keys=True,
cls=ThreadEncoder,
)
)
else:
click.echo_via_pager(
generate_thread_output(sort_threads(matched_threads, sort_by=sort_by))
)

View File

@@ -1,6 +1,5 @@
# pylint: disable=old-style-class # pylint: disable=old-style-class
import os import os
import json
from colorama import Fore, Style from colorama import Fore, Style
from .scores import get_vote_color from .scores import get_vote_color
@@ -12,17 +11,6 @@ class Post:
self.user = user self.user = user
class PostEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Post):
return dict(
body=o.body,
score=o.score,
user=o.user,
)
return json.JSONEncoder.default(self, o)
def get_terminal_width(): def get_terminal_width():
_, columns = os.popen("stty size", "r").read().split() _, columns = os.popen("stty size", "r").read().split()
return int(columns) return int(columns)

View File

@@ -1,5 +1,4 @@
import re import re
import json
from colorama import Fore, Style from colorama import Fore, Style
from . import API_BASE_URL from . import API_BASE_URL
from .scores import calculate_score, get_vote_color from .scores import calculate_score, get_vote_color
@@ -17,19 +16,6 @@ class Thread:
return f"Thread({self.title})" return f"Thread({self.title})"
class ThreadEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Thread):
return dict(
dealer_name=o.dealer_name,
score=o.score,
title=o.title,
url=o.url,
views=o.views,
)
return json.JSONEncoder.default(self, o)
def build_web_path(slug): def build_web_path(slug):
return f"{API_BASE_URL}{slug}" return f"{API_BASE_URL}{slug}"