Giter VIP home page Giter VIP logo

snoots's Introduction

This repository is archived

I have lost interest in the project. Reddit's API is awfully designed and really not fun to work with, and all the projects I had in mind that inspired me to start this project have since fallen through or been shut down.

Additionally, Reddit's recent decision to effectively kill 3rd party applications with their API costs, and the continued public slander, misinformation, broken promises, and lack of care about accessibility by Reddit's leadership[1][2][3] has made me not want to have anything further to do with reddit or their API until and unless things change.

If Reddit makes steps to fix what they have broken, both their relations with their users and their API, then I might revive this project. But unless that happens this project is dead.


snoots

semantic release latest release latest stable release checks status coverage

npm version npm types weekly npm downloads npm dependents license

A modern, fully-featured, strongly-typed reddit api wrapper.

⚠️ WARNING ⚠️

This project is in early alpha. Things can (and likely will) change at any time for any reason without warning, and large parts of the api are not yet supported. If you need a stable reddit api today, use snoowrap.

If you want to help guide the future of the project towards v1.0.0, please check out this discussion!

Installation

npm i snoots@dev

Note: Node 14+ is required.

Documentation

For detailed instructions on how to use snoots, check out the latest documentation.

Contributing

If you want to help out, please read the CONTRIBUTING.md.

snoots's People

Contributors

cachho avatar renovate[bot] avatar semantic-release-bot avatar thislooksfun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

snoots's Issues

Test that different auths request different grants.

Using a TokenAuth should request a `refresh_token` grant. Using a UsernameAuth should request a `password` grant, and using no auth should request a client_credentials grant. This is currently pending nock/nock#2171.


// TODO: Test that different auths request different grants.
// BODY: Using a TokenAuth should request a `refresh_token` grant. Using a
// BODY: UsernameAuth should request a `password` grant, and using no auth
// BODY: should request a client_credentials grant. This is currently
// BODY: pending https://github.com/nock/nock/issues/2171.
});


This issue was generated by todo based on a TODO comment in 7391759. It's been assigned to @thislooksfun because they committed the code.

Suspended users give back a very minimal response.

Fetching a suspended user gives back very minimal data, meaning that this typing below is only a valid base for non-suspended users. I'm not sure what the best way to deal with this is...


// TODO: Suspended users give back a very minimal response.
// BODY: Fetching a suspended user gives back very minimal data, meaning that
// BODY: this typing below is only a valid base for non-suspended users. I'm not
// BODY: sure what the best way to deal with this is...
/** The data for a single Reddit user. */


This issue was generated by todo based on a TODO comment in bd0fc8b. It's been assigned to @thislooksfun because they committed the code.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): update all non-major dev dependencies (@commitlint/cli, @commitlint/config-conventional, @semantic-release/github, @semantic-release/npm, @semantic-release/release-notes-generator, @types/debug, @types/jest, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, eslint, fast-check, semantic-release, typedoc, typescript)
  • chore(deps): update semantic-release monorepo (major) (@semantic-release/commit-analyzer, @semantic-release/github)

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/codeql-analysis.yml
  • actions/checkout v3
  • github/codeql-action v2
  • github/codeql-action v2
  • github/codeql-action v2
.github/workflows/commitlint.yaml
  • actions/checkout v3
  • wagoid/commitlint-github-action v5
.github/workflows/document.yaml
  • actions/checkout v3
  • actions/setup-node v3
  • actions/github-script v6
  • JamesIves/github-pages-deploy-action v4
.github/workflows/release.yaml
  • actions/checkout v3
  • actions/setup-node v3
  • codfish/semantic-release-action v2
  • actions/checkout v3
  • actions/setup-node v3
  • actions/github-script v6
  • JamesIves/github-pages-deploy-action v4
.github/workflows/symlink.yaml
  • actions/checkout v3
  • actions/setup-node v3
.github/workflows/test.yaml
  • actions/checkout v3
  • actions/setup-node v3
  • codecov/codecov-action v3
npm
package.json
  • camelcase ^6.3.0
  • debug ^4.3.4
  • got ^11.8.6
  • tslib ^2.5.0
  • @commitlint/cli 17.6.3
  • @commitlint/config-conventional 17.6.3
  • @semantic-release/changelog 6.0.3
  • @semantic-release/commit-analyzer 9.0.2
  • @semantic-release/git 10.0.1
  • @semantic-release/github 8.0.7
  • @semantic-release/npm 10.0.3
  • @semantic-release/release-notes-generator 11.0.1
  • @types/debug 4.1.7
  • @types/jest 29.5.1
  • @typescript-eslint/eslint-plugin 5.59.5
  • @typescript-eslint/parser 5.59.5
  • del-cli 5.0.0
  • eslint 8.40.0
  • eslint-config-prettier 8.8.0
  • eslint-plugin-comment-length 0.9.3
  • eslint-plugin-deprecation 1.4.1
  • eslint-plugin-eslint-comments 3.2.0
  • eslint-plugin-import 2.27.5
  • eslint-plugin-jest 27.2.1
  • eslint-plugin-prettier 4.2.1
  • eslint-plugin-promise 6.1.1
  • eslint-plugin-simple-import-sort 10.0.0
  • eslint-plugin-sonarjs 0.19.0
  • eslint-plugin-unicorn 47.0.0
  • fast-check 3.8.1
  • husky 8.0.3
  • is-ci 3.0.1
  • jest 29.5.0
  • lint-staged 13.2.2
  • nock 13.3.1
  • npm-run-all 4.1.5
  • prettier 2.8.8
  • semantic-release 21.0.2
  • supports-color 9.3.1
  • ts-jest 29.1.0
  • typedoc 0.24.7
  • typescript 5.0.4
  • node >= 14
nvm
.nvmrc
  • node 18

  • Check this box to trigger a request for Renovate to run again on this repository

Feature parity with snoowrap

There are still several large areas of the codebase that need work before snoots has feature-parity with snoowrap. For a full class-by-class rundown of what is missing see below. If you have a specific needs that snoots doesn't currently meet, please let me know so I can prioritize accordingly!

Snoowrap Classes:

Notes/caveats:

  • This is comparing [email protected] against [email protected].
  • The names used here are snoowrap's names. snoots' naming scheme is often different.
  • I tried to be as complete as possible but it's likely I missed something.
  • This does not cover any method parameters, just the methods themselves.
  • This is a live list, it will be updated as compatibility improves.

snoowrap

RedditContent (base class for all items)

ReplyableContent (extends RedditContent)

✅ Full feature parity.

VoteableContent (extends ReplyableContent)

  • Missing properties
    • author_flair_background_color
    • author_flair_css_class
    • author_flair_richtext
    • author_flair_template_id
    • author_flair_text_color
    • author_flair_text
    • author_flair_type
    • author_fullname1
    • downs1
    • no_follow
    • removal_reason
    • report_reasons
    • subreddit_id1
    • subreddit_name_prefixed1
    • ups1

Comment (extends VoteableContent)

  • Missing properties
    • collapsed_reason
    • controversiality
    • depth
  • Missing methods

RedditUser (extends RedditContent)

Submission (extends VoteableContent)

  • Missing properties
    • clicked
    • content_categories
    • link_flair_background_color
    • link_flair_css_class
    • link_flair_richtext
    • link_flair_template_id
    • link_flair_text_color
    • link_flair_text
    • link_flair_type
    • media_embed
    • media_only
    • media
    • parent_whitelist_status
    • post_hint
    • preview
    • previous_visits
    • pwls2
    • quarantine
    • removal_reason
    • removed_by_category
    • secure_media_embed
    • secure_media
    • selftext_html
    • selftext
    • thumbnail
    • view_count
    • visited
    • whitelist_status
    • wls2
  • Missing Methods

LiveThread (extends RedditContent)

❌ Unimplemented

PrivateMessage (extends ReplyableContent)

❌ Unimplemented

Subreddit (extends RedditContent)

MultiReddit (extends RedditContent)

❌ Unimplemented

ModmailConversation (extends RedditContent)

❌ Unimplemented

ModmailConversationAuthor (extends RedditContent)

❌ Unimplemented

WikiPage (extends RedditContent)

❌ Unimplemented

Listing

✅ Feature parity, but implemented very differently.


1This will not be implemented.
2This is unlikely to be implemented.
3This relates to private messaging, which is an ongoing discussion.

Post.removed always undefined

Tracks progress towards #31.

To Reproduce
Post ID: nmftww

Expected behavior
A clear and concise description of what you expected to happen.

Comment replies broken

Describe the issue

I've been trying to get the comments for a post, rather unsuccessfully. I don't know if there is a bug or I'm doing something wrong (can post a gist or two if that's helpful). I've tried a number of different techniques and api calls, but with mixed success. I'm sure a working example is easy to hack together - would really appreciate it.

Add dotenv and dotenv-expand as dependency for tests

Feature Description

The Problem

I can't write jest tests without including secrets in the file itself, meaning I can't commit working tests

The Rationale

I'd like to start writing some tests for the features I've implemented (modnotes and wiki pages) and commit them to the repository, but I'm currently unable to do so as all my secrets are in the clear. By adding dotenv and dotenv-expand, a shared .env file could be added to the .gitignore file (updated as necessary for new tests). This will improve code coverage, and possibly allow test suites to be run on commit.

`await post.comments.empty()` results in "Unable to fetch next page"

What happened?

Not sure if bug, or I'm using it wrong (sorry if so!). Pls advise on how to get comments for a post. I had assumed I could get the comments directly from a Post, but... The following blows up with the error "Unable to fetch next page" (see the Pager class in dist/reddit/listing/listing.js line 12):

import {Client} from "snoots";

const MyGateway = require("./MyGateway.js");

const name = "foo";
const clientId = "foo";
const version = "v0.1";
const clientSecret = "foo";

const userAgent = `typescript:${name}:${version}`;

...
    const subredditName = "MachineLearning";
    const subReddit = await client.subreddits.fetch(subredditName);

    const searchSyntax = "cloudsearch"// "cloudsearch" | "lucene" | "plain";
    const sort = "comments";// "relevance" | "hot" | "top" | "new" | "comments"
    const time = "year";// "hour" | "day" | "week" | "month" | "year" | "all"
    const posts = await subReddit.search("lstm", time, sort, searchSyntax);

    let i = 0;

    for await (const post of posts) {
        console.log(`${++i} ${post.id} ${post.title}: ${post.url}`);
        
        const isEmpty = await post.comments.empty();//          <---- this blows up
        if (isEmpty)
            continue;

        const comment = await post.comments.first();
        console.log(`\t${comment.body}`);
    }

Reproduction steps

  1. Run the above (substituting the initial params)

Snoots Version

1.0.0-dev.22

Node Version

v16

Logs

1 t8fn7m [D] Are we at the end of an era where ML could be explained rigorously using mathematics?: https://www.reddit.com/r/MachineLearning/comments/t8fn7m/d_are_we_at_the_end_of_an_era_where_ml_could_be/
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Unable to fetch next page".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

Extra Information

No response

Remove this as we move to release v1.0.0

# # TODO: Remove this as we move to release v1.0.0
# - if: steps.semrel.outputs.new-release-published == 'true'
# run: |
# npm config set registry https://registry.npmjs.org/
# npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
# npm dist-tag add snoots@${{ steps.semrel.outputs.release-version }} latest


This issue was generated by todo based on a TODO comment in 4a82ca4. It's been assigned to @thislooksfun because they committed the code.

Implement versioned docs.

The other commented sections need to be resolved at the same time as this in order to implement this properly. This is pending JamesIves/github-pages-deploy-action#635.


# TODO: Implement versioned docs.
# BODY: The other commented sections need to be resolved at the same time as
# BODY: this in order to implement this properly.
# BODY: This is pending JamesIves/github-pages-deploy-action#635.
# release:
# types: [published]


This issue was generated by todo based on a TODO comment in 154ee30. It's been assigned to @thislooksfun because they committed the code.

Modnotes

Feature Description

Moderator Notes

I feel like there should be a discussion on how/where modnotes are implemented, as a call to the API requires both a subreddit and a username. There are several questions then on how it should be implemented:

  • Should Modnotes be implemented on a subreddit object or a user object, or both?
  • Should modnotes have its own controller and defined on the client class?
  • Should it take subreddits and users as strings (usernames) or as snoot objects? or both?

Typings

There are also issues on the typings of what is returned from the API calls themselves. I've put an example below:

type ModNoteTypeFilter = 'NOTE' | 'APPROVAL' | 'REMOVAL' | 'BAN' | 'MUTE' | 'INVITE' | 'SPAM' | 'CONTENT_CHANGE' | 'MOD_ACTION' | 'ALL' ;
export interface ModeratorNote {
  subreddit_id: string; // t5
  operator_id: string; // t2
  mod_action_data : {
    action: string;
    reddit_id: string;  // t1 or t3
    details: string;
    description: null // Not sure what the type is of this
  };
  subreddit: string;
  user: string;
  operator: string;
  id: string;
  user_note_data: {
    note: null;  // Not sure what the type is of this
    reddit_id: string; // t1 or t3
    label: null  // Not sure what the type is of this
  }
  user_id: string;  // t2
  created_at: number;
  cursor: string;
  type: ModNoteTypeFilter
}

I imagine ModeratorNote.user_note_data.label is defined as "(BOT_BAN, PERMA_BAN, BAN, ABUSE_WARNING, SPAM_WARNING, SPAM_WATCH, SOLID_CONTRIBUTOR, HELPFUL_USER)" by the API (optionally null).

Added features?

There is a good opportunity here to transform subreddit_ids, operator_ids and reddit_ids into their respective objects, or even to have a Modnote class with the appropriate methods for generating these objects.

API Endpoints

I'm listing these here just to make the discussion a touch easier


DELETE /api/mod/notes
Delete a mod user note where type=NOTE. Query params:

  • note_id: a unique ID for the note to be deleted (should have a ModNote_ prefix)
  • subreddit: subreddit name (not prefixed, from what I can tell)
  • username account username (also not prefixed)

GET /api/mod/notes
Get mod notes for a specific user in a given subreddit. Query params:

  • before: (optional) an encoded string used for pagination with mod notes
  • filter: (optional) one of (NOTE, APPROVAL, REMOVAL, BAN, MUTE, INVITE, SPAM, CONTENT_CHANGE, MOD_ACTION, ALL), to be used for querying specific types of mod notes (default: all)
  • limit: (optional) the number of mod notes to return in the response payload (default: 25, max: 100)'}
  • subreddit: subreddit name (not prefixed, from what I can tell)
  • username account username (also not prefixed)

POST /api/mod/notes
Create a mod user note where type=NOTE. Query params:

  • label: (optional) one of (BOT_BAN, PERMA_BAN, BAN, ABUSE_WARNING, SPAM_WARNING, SPAM_WATCH, SOLID_CONTRIBUTOR, HELPFUL_USER)
  • note: Content of the note, should be a string with a maximum character limit of 250
  • reddit_id: (optional) a fullname of a comment or post (should have either a t1 or t3 prefix)
  • subreddit: subreddit name (not prefixed, from what I can tell)
  • username account username (also not prefixed)

GET /api/mod/notes/recent
Fetch the most recent notes written by a moderator

Both parameters should be comma separated lists of equal lengths. The first subreddit will be paired with the first account to represent a query for a mod written note for that account in that subreddit and so forth for all subsequent pairs of subreddits and accounts. This request accepts up to 500 pairs of subreddit names and usernames. Parameters should be passed as query parameters.

The response will be a list of mod notes in the order that subreddits and accounts were given. If no note exist for a given subreddit/account pair, then null will take its place in the list.

  • subreddits: a comma delimited list of subreddits by name
  • usernames account usernames

Thanks :)

This TEMPORARILY bypasses the release job.

This should be made to require the release job before v1.0.0. At that point we can likely also remove the 'if' clause here since that is accounted for by requiring 'release'.


# TODO: This TEMPORARILY bypasses the release job.
# BODY: This should be made to require the release job before v1.0.0. At
# BODY: that point we can likely also remove the 'if' clause here since that
# BODY: is accounted for by requiring 'release'.
# needs: [release]
if: github.event_name == 'push' && github.ref == 'refs/heads/master'


This issue was generated by todo based on a TODO comment in efa4944. It's been assigned to @thislooksfun because they committed the code.

The user fetch does return some info about this subreddit, just not

// TODO: The user fetch does return some info about this subreddit, just not
// enough to populate a full Subreddit instance. Is there some way we could
// make use of that partial data?
return this.controls.getClient().subreddits.fetch(`u_${this.name}`);
}


This issue was generated by todo based on a TODO comment in bd0fc8b. It's been assigned to @thislooksfun because they committed the code.

Switch to native `fetch()`

Node 17.5.0 adds an implementation of fetch(). This is great as it will allow dropping got as a dependency, which will, in turn, allow for snoots to work in the browser (perhaps not out-of-the-gate, but still).

The catch is that the fetch() implementation is experimental and also currently only in the latest odd release. Once it becomes stable in an LTS release we should switch to it.

Add the ability to fetch the list of contributors

Discussed in #48

Originally posted by adri326 March 26, 2022
While I was trying out this library, I hit a roadblock: there seems to be no API for the /r/<subreddit>/about/contributors endpoint. I also couldn't find a straightforward way to bridge that gap myself, without going ahead and changing the source code of snoots myself.

Hopefully this can be added in the future!

RedditListing.children is not always of type RedditObject[]

What happened?

export interface RedditListing {
  after?: string;
  before?: string;
  children: RedditObject[];
  dist?: number;
  modhash?: string;
}

RedditListing.children is defined as type RedditObject[], however, not all listings contain a field children of type RedditObject[]. This is most readily observed in the wiki revisions listing being worked on in #87, where children is an array of POD.

Reproduction steps

n/a

Snoots Version

all

Node Version

n/a

Logs

No response

Extra Information

No response

This doesn't seem to be working, but I don't know why.

It runs fine on workflow_run, but not on branch push.


# TODO: This doesn't seem to be working, but I don't know why.
# BODY: It runs fine on workflow_run, but not on branch push.
branches: ["gh-pages"]
workflow_run:
workflows: ["Publish Documentation", "Release"]


This issue was generated by todo based on a TODO comment in 29ab531. It's been assigned to @thislooksfun because they committed the code.

RequestError: connect ECONNREFUSED 127.0.0.1:443

 const snoots = require('snoots');
    const client = new snoots.Client({
        userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36',
        creds: {
            clientId: 'Ox0zdas',
            clientSecret: 'ad0-asd',
        },

 
        auth:{
            username:'adsd',
            password:"adsd"
        }

    });

    const sub = await client.subreddits.fetch("funny");
    const post = await sub.getRandomPost();
    const title = post.title;


Error:


RequestError: connect ECONNREFUSED 127.0.0.1:443
    at ClientRequest.<anonymous> (/Users/dasdasd/Desktop/projects/asdasd/node_modules/snoots/node_modules/got/dist/source/core/index.js:962:111)
    at Object.onceWrapper (events.js:520:26)
    at ClientRequest.emit (events.js:412:35)
    at ClientRequest.emit (domain.js:475:12)
    at ClientRequest.origin.emit (/Users/dasdasd/Desktop/projects/asdasd/node_modules/snoots/node_modules/@szmarczak/http-timer/dist/source/index.js:43:20)
    at TLSSocket.socketErrorListener (_http_client.js:475:9)
    at TLSSocket.emit (events.js:400:28)
    at TLSSocket.emit (domain.js:475:12)
    at emitErrorNT (internal/streams/destroy.js:106:8)
    at emitErrorCloseNT (internal/streams/destroy.js:74:3)
    at processTicksAndRejections (internal/process/task_queues.js:82:21)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16) {
  code: 'ECONNREFUSED',
  timings: {
    start: 1644514843612,
    socket: 1644514843614,
    lookup: 1644514843614,
    connect: undefined,
    secureConnect: undefined,
    upload: undefined,
    response: undefined,
    end: undefined,
    error: 1644514843615,
    abort: undefined,
    phases: {
      wait: 2,
      dns: 0,
      tcp: undefined,
      tls: undefined,
      request: undefined,
      firstByte: undefined,
      download: undefined,
      total: 3
    }
  }


Node version:

v14.18.1

Client creds-style auth gives 401 when ran from firebase function

What happened?

When creating a Client with my Reddit app creds, it works from NodeJS REPL, but same code running inside firebase function gives 401.

It appears the app secret is not present in the password field of the request options.

Reproduction steps

Create a new Client(userAgent: “something”, creds:{clientId: “cid”, secretId: “ckey”});

Making Reddit API requests works correctly from Node REPL, but not from Firebase function. (Ran locally OR hosted)

Snoots Version

dev latest

Node Version

v16

Logs

401 from got pkg.

Extra Information

No response

Expose scopes of current authentication

Currently we just discard the auth scope(s), but some users rely on being able to query it. We should allow them to do so.

export interface TokenResponse {
accessToken: string;
tokenType: string;
expiresIn: number;
refreshToken?: string;
scope: string;
}
function rawToToken(raw: Data): Token {
const tkns: TokenResponse = camelCaseKeys(raw);
return {
access: tkns.accessToken,
expiration: Date.now() + tkns.expiresIn * 1000,
refresh: tkns.refreshToken,
};
}

Add E2E testing

Currently there is only (incomplete) unit testing. This is great, as long as the Reddit API stays stable, which it won't. Unfortunately adding unit testing is non trivial since the endpoints are (rightly) rate-limited, which makes automated testing really annoying.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.