mira

package module
v1.1.3-0...-698eee3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 8, 2022 License: Apache-2.0 Imports: 14 Imported by: 0

README

mira

Go Report Card Build Status GoDoc PRs Welcome

For full documentation, please see the Godoc page

mira is a Reddit Api Wrapper written in beautiful Go.

It is super simple to use the bot as we also provide you with simple but fully extensive interfaces. Currently, mira is a project that is considered more or less complete. All main functionality, such as streaming, data manipulation, data request, submissions, links, etc. are fully implemented. mira can be extended to use any Reddit API endpoint. More details at the bottom of this page.

Demo

Demo

Two quick notes: all actions should be done via Reddit struct, I thought it would make it simpler to work with. Secondly, all actions require the objects full thing_id, so you have to use GetId() to get that id. Every struct has that method implemented and it will return a string in the form of t[1-6]_[a-z0-9]{5}. Refer to the following table for the classifications of the structs.

Type Prefixes

Prefix Type
t1 Comment
t2 Redditor
t3 Submission, PostListing contents
t4 Message (NOT IMPLEMENTED)
t5 Subreddit
t6 Award (NOT IMPLEMENTED)

Config file

The config file structure is very simple:

login.conf
----------
CLIENT_ID =
CLIENT_SECRET =
USERNAME =
PASSWORD =
USER_AGENT =
r, err := mira.Init(mira.ReadCredsFromFile("login.conf"))

Environment setup

Mira also works with environmental variables, here is an example from docker-compose

    environment:
      - BOT_CLIENT_ID=hunteoahtnhnt432
      - BOT_CLIENT_SECRET=ehoantehont4ht34hnt332
      - BOT_USER_AGENT='u/mytestbot developed by thecsw'
      - BOT_USERNAME=mytestbot
      - BOT_PASSWORD=verygoodpassword

And the login will look like this:

r, err := mira.Init(mira.ReadCredsFromEnv())

Or you can always just fill in the values directly.

Examples

Note: Error checking is omitted for brevity.

Streaming

Streaming new submissions is very simple! mira supports streaming comment replies, mentions, new subreddit's/redditor's comments, and new subreddit's/redditor's submissions.

// r is an instance of *mira.Reddit
r, err := mira.Init(mira.ReadCredsFromFile("login.conf"))

// Start streaming my comment replies
c, err := r.StreamCommentReplies()
for {
	msg := <-c
	r.Comment(msg.GetId()).Reply("I got your message!")
}

// Start streaming my mentions
// Start streaming my comment replies
c, err := r.StreamMentions()
for {
	msg := <-c
	r.Comment(msg.GetId()).Reply("I got your mention of me!")
}

// Start streaming subreddits' submissions
c, err := r.Subreddit("tifu", "wholesomememes").StreamSubmissions()
for {
	post := <-c
	r.Submission(post.GetId()).Save("hello there")
}

// NOTE: Second value is the stop channel. Send a true value
// to the stop channel and the goroutine will return. 
// Basically, `stop <- true`

// Start streaming subreddits' comments
c, err := r.Subreddit("all").StreamComments()
for {
	msg := <-c
	r.Comment(msg.GetId()).Reply("my reply!")
}

// Start streaming redditor's submissions
c, err := r.Redditor("thecsw").StreamSubmissions()
for {
	post := <-c
	r.Submission(post.GetId()).Save("hello there")
}
	
// Start streaming redditor' comments
c, err := r.Redditor("thecsw").StreamComments()
for {
	msg := <-c
	r.Comment(msg.GetId()).Reply("my reply!")
}

Submitting, Commenting, Replying, and Editing

It is very easy to post a submission, comment on it, reply to a message, or edit a comment.

package main

import (
	"fmt"

	"github.com/thecsw/mira"
)

// Error checking is omitted for brevity
func main() {
	r, err := mira.Init(mira.ReadCredsFromFile("login.conf"))

	// Make a submission
	post, err := r.Subreddit("mysubreddit").Submit("mytitle", "mytext")

	// Comment on our new submission
	comment, err := r.Submission(post.GetId()).Save("mycomment")

	// Reply to our own comment
	reply, err := r.Comment(comment.GetId()).Reply("myreply")

	// Delete the reply
	r.Comment(reply.GetId()).Delete()

	// Edit the first comment
	newComment, err := r.Comment(comment.GetId()).Edit("myedit")

	// Show the comment's body
	fmt.Println(newComment.GetBody())
}

Composing a message

We can also send a message to another user!

package main

import (
	"github.com/thecsw/mira"
)

func main() {
	r, err := mira.Init(mira.ReadCredsFromFile("login.conf"))

	r.Redditor("myuser").Compose("mytitle", "mytext")
}

Going through hot, new, top, rising, controversial, and random

You can also traverse through a number of submissions using one of our methods.

package main

import (
	"fmt"

	"github.com/thecsw/mira"
)

func main() {
	r, err := mira.Init(mira.ReadCredsFromFile("login.conf"))
	sort := "top"
	var limit int = 25
	duration := "all"
	subs, err := r.Subreddit("all").Submissions(sort, duration, limit)
	for _, v := range subs {
		fmt.Println("Submission Title: ", v.GetTitle())
	}
}

Getting reddit info

You can extract info from any reddit ID using mira. The returned value is an instance of mira.MiraInterface.

package main

import (
	"fmt"

	"github.com/thecsw/mira"
)

func main() {
	r, err := mira.Init(mira.ReadCredsFromFile("login.conf"))
	me, err := r.Me().Info()
	comment, err := r.Comment("t1_...").Info()
	redditor, err := r.Redditor("t2_...").Info()
	submission, err := r.Submission("t3_...").Info()
	subreddit, err := r.Subreddit("t5_...").Info()
}

Here is the interface:

type MiraInterface interface {
	GetId() string
	GetParentId() string
	GetTitle() string
	GetBody() string
	GetAuthor() string
	GetName() string
	GetKarma() float64
	GetUps() float64
	GetDowns() float64
	GetSubreddit() string
	GetCreated() float64
	GetFlair() string
	GetUrl() string
	IsRoot() bool
}

Mira Caller

Surely, Reddit API is always developing and I can't implement all endpoints. It will be a bit of a bloat. Instead, you have accessto *Reddit.MiraRequest method that will let you to do any custom reddit api calls!

Here is the signature:

func (c *Reddit) MiraRequest(method string, target string, payload map[string]string) ([]byte, error) {...}

It is pretty straight-forward. The return is a slice of bytes. Parse it yourself.

Here is an example of how Reddit.Reply() uses MiraRequest:

NOTE: checkType(...) is a quick method to pop a value from the queue and make sure it's a valid value and type. For example,

r.Comment("COMM1").Submission("SUBM1").Redditor("USER1")

will add elements to its internal queue, so that the layout is:

Enqueue->
              redditor  submission  comment               // type
	|BACK| -> |USER1| -> |SUBM1| -> |COMM1| -> |FRONT|    // value
                                                  Dequeue->

So that when you run r.checkType("comment"), it will dequeue COMM1 and return triplet "COMM1", "comment", nil.

If you run r.checkType("redditor") (will fail because subm is at the end), you will get "", "", "errors.New("the passed type...")

Here is an example of how you check that the last element to dequeue is a type that you're expecting:

func (c *Reddit) Reply(text string) (models.CommentWrap, error) {
	ret := &models.CommentWrap{}
	// Second return is type, which is "comment"
	name, _, err := c.checkType("comment")
	if err != nil {
		return *ret, err
	}
	target := RedditOauth + "/api/comment"
	ans, err := c.MiraRequest("POST", target, map[string]string{
		"text":     text,
		"thing_id": name,
		"api_type": "json",
	})
	json.Unmarshal(ans, ret)
	return *ret, err
}

Documentation

Overview

Package mira is fantastic reddit api wrapper

README at https://github.com/thecsw/mira

All function docs here

Index

Constants

View Source
const (
	// RedditBase is the basic reddit base URL, authed is the base URL for use once authenticated
	RedditBase = "https://www.reddit.com/"
	// RedditOauth is the oauth url to pass the tokens to
	RedditOauth = "https://oauth.reddit.com"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ChainVals

type ChainVals struct {
	Name string
	Type string
}

ChainVals is our queue values

type Credentials

type Credentials struct {
	ClientID     string
	ClientSecret string
	Username     string
	Password     string
	UserAgent    string
}

func ReadCredsFromEnv

func ReadCredsFromEnv() Credentials

ReadCredsFromEnv reads mira credentials from environment

func ReadCredsFromFile

func ReadCredsFromFile(file string) Credentials

ReadCredsFromFile reads mira credentials from a given file path

type MiraInterface

type MiraInterface interface {
	GetId() string
	GetParentId() string
	GetTitle() string
	GetBody() string
	GetAuthor() string
	GetName() string
	GetKarma() float64
	GetUps() float64
	GetDowns() float64
	GetSubreddit() string
	GetCreated() float64
	GetFlair() string
	GetUrl() string
	IsRoot() bool
}

MiraInterface is the interface that unites most of the reddit objects that mira uses and exposes some of the most used methods

type Reddit

type Reddit struct {
	Token    string  `json:"access_token"`
	Duration float64 `json:"expires_in"`
	Creds    Credentials
	Chain    chan *ChainVals
	Stream   Streaming
	Values   RedditVals
	Client   *http.Client
}

Reddit is the main mira struct that practically does everything

func Authenticate

func Authenticate(c *Credentials) (*Reddit, error)

Authenticate returns *Reddit object that has been authed

func Init

func Init(c Credentials) (*Reddit, error)

Init is used when we initialize the Reddit instance, automatically start a goroutine that will update the token every 45 minutes. The auto_refresh should not be accessible to the end user as it is an internal method

func (*Reddit) Approve

func (c *Reddit) Approve() error

Approve is a mod tool to approve a comment or a submission Will fail if not a mod.

func (*Reddit) Comment

func (c *Reddit) Comment(name string) *Reddit

Comment pushes a new comment value to the internal queue.

func (*Reddit) Comments

func (c *Reddit) Comments(sort string, tdur string, limit int) ([]models.Comment, error)

Comments returns comments from a subreddit up to a specified limit sorted by the given parameters

Sorting options: "hot", "new", "top", "rising", "controversial", "random"

Duration options: "hour", "day", "week", "year", "all"

Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) CommentsAfter

func (c *Reddit) CommentsAfter(sort string, last string, limit int) ([]models.Comment, error)

CommentsAfter returns new comments from a subreddit

Last is the anchor of a comment id

Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) Compose

func (c *Reddit) Compose(subject, text string) error

Compose will send a message to next redditor.

func (*Reddit) Delete

func (c *Reddit) Delete() error

Delete deletes whatever is next in the queue.

func (*Reddit) Distinguish

func (c *Reddit) Distinguish(how string, sticky bool) error

Distinguish is a mod tool to distinguish a comment or a submission Will fail if not a mod.

func (*Reddit) Edit

func (c *Reddit) Edit(text string) (models.CommentWrap, error)

Edit will edit the next queued comment.

func (*Reddit) ExtractSubmission

func (c *Reddit) ExtractSubmission() (string, error)

ExtractSubmission extracts submission id from last pushed object does not make an api call like .Root(), use this instead.

func (*Reddit) Info

func (c *Reddit) Info() (MiraInterface, error)

Info returns MiraInterface of last pushed object.

func (*Reddit) ListUnreadMessages

func (c *Reddit) ListUnreadMessages() ([]models.Comment, error)

ListUnreadMessages returns a list of all unread messages.

func (*Reddit) Me

func (c *Reddit) Me() *Reddit

Me pushes a new Redditor value.

func (*Reddit) MiraRequest

func (c *Reddit) MiraRequest(method string, target string, payload map[string]string) ([]byte, error)

MiraRequest Reddit API is always developing and I can't implement all endpoints; It will be a bit of a bloat; Instead, you have accessto *Reddit.MiraRequest method that will let you to do any custom reddit api calls!

Here is the signature:

func (c *Reddit) MiraRequest(method string, target string, payload map[string]string) ([]byte, error) {...}

It is pretty straight-forward, the return is a slice of bytes; Parse it yourself.

func (*Reddit) ModQueue

func (c *Reddit) ModQueue(limit int) ([]models.ModQueueListingChild, error)

ModQueue returns modqueue entries from a subreddit up to a specified limit sorted by the given parameters Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) ModQueueAfter

func (c *Reddit) ModQueueAfter(last string, limit int) ([]models.ModQueueListingChild, error)

ModQueueAfter returns new modqueue entries from a subreddit

Last is the anchor of a modqueue entry id

Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) ReadAllMessages

func (c *Reddit) ReadAllMessages() error

ReadAllMessages uses ReadMessage on all unread messages.

func (*Reddit) ReadMessage

func (c *Reddit) ReadMessage(messageID string) error

ReadMessage marks the next comment/message as read.

func (*Reddit) Redditor

func (c *Reddit) Redditor(name string) *Reddit

Redditor pushes a new redditor value to the internal queue.

func (*Reddit) Reply

func (c *Reddit) Reply(text string) (models.CommentWrap, error)

Reply replies to a comment with text.

func (*Reddit) ReplyWithID

func (c *Reddit) ReplyWithID(name, text string) (models.CommentWrap, error)

ReplyWithID is the same as Reply but with explicit passing comment id.

func (*Reddit) Reports

func (c *Reddit) Reports(limit int) ([]models.ModQueueListingChild, error)

Reports returns report entries from a subreddit up to a specified limit sorted by the given parameters Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) ReportsAfter

func (c *Reddit) ReportsAfter(last string, limit int) ([]models.ModQueueListingChild, error)

ReportsAfter returns new report entries from a subreddit

Last is the anchor of a modqueue entry id

Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) Root

func (c *Reddit) Root() (string, error)

Root will return the submission id of a comment Very expensive on API calls, please use .ExtractSubmission() instead.

func (*Reddit) Save

func (c *Reddit) Save(text string) (models.CommentWrap, error)

Save posts a comment to a submission.

func (*Reddit) SaveWithID

func (c *Reddit) SaveWithID(name, text string) (models.CommentWrap, error)

SaveWithID is the same as Save but with explicitely passing.

func (*Reddit) SelectFlair

func (c *Reddit) SelectFlair(text string) error

SelectFlair sets a submission flair.

func (*Reddit) SelectFlairWithID

func (c *Reddit) SelectFlairWithID(name, text string) error

SelectFlairWithID sets submission flair with explicit ID.

func (*Reddit) SetClient

func (c *Reddit) SetClient(client *http.Client)

SetClient sets mira's *http.Client to make requests

func (*Reddit) SetDefault

func (c *Reddit) SetDefault()

SetDefault sets all default values

func (*Reddit) StreamCommentReplies

func (c *Reddit) StreamCommentReplies() <-chan models.Comment

StreamCommentReplies streams comment replies c is the channel with all unread messages

func (*Reddit) StreamComments

func (c *Reddit) StreamComments() (<-chan models.Comment, error)

StreamComments streams comments from a redditor or a subreddit c is the channel with all comments

func (*Reddit) StreamMentions

func (c *Reddit) StreamMentions() <-chan models.Comment

StreamMentions streams recent mentions c is the channel with all unread messages

func (*Reddit) StreamModQueue

func (c *Reddit) StreamModQueue() (<-chan models.PostListingChild, error)

StreamModQueue streams modqueue entries from a subreddit c is the channel with all modqueue entries.

func (*Reddit) StreamReports

func (c *Reddit) StreamReports() (<-chan models.ReportListingChild, error)

StreamReports streams reports entries from a subreddit c is the channel with all report entries.

func (*Reddit) StreamSubmissions

func (c *Reddit) StreamSubmissions() (<-chan models.PostListingChild, error)

StreamSubmissions streams submissions from a redditor or a subreddit c is the channel with all submissions.

func (*Reddit) Submission

func (c *Reddit) Submission(name string) *Reddit

Submission pushes a new submission value to the internal queue.

func (*Reddit) Submissions

func (c *Reddit) Submissions(sort string, tdur string, limit int) ([]models.PostListingChild, error)

Submissions returns submissions from a subreddit up to a specified limit sorted by the given parameters

Sorting options: "hot", "new", "top", "rising", "controversial", "random"

Duration options: "hour", "day", "week", "year", "all"

Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) SubmissionsAfter

func (c *Reddit) SubmissionsAfter(last string, limit int) ([]models.PostListingChild, error)

SubmissionsAfter returns new submissions from a subreddit

Last is the anchor of a submission id

Limit is any numerical value, so 0 <= limit <= 100.

func (*Reddit) Submit

func (c *Reddit) Submit(title string, text string) (models.Submission, error)

Submit submits a submission to a subreddit.

func (*Reddit) Subreddit

func (c *Reddit) Subreddit(name ...string) *Reddit

Subreddit pushes a new subreddit value to the internal queue.

func (*Reddit) UpdateSidebar

func (c *Reddit) UpdateSidebar(text string) error

UpdateSidebar updates subreddit's sidebar, Needs mod privileges.

func (*Reddit) UserFlair

func (c *Reddit) UserFlair(user, text string) error

UserFlair updates user's flair in a sub. Needs mod permissions.

func (*Reddit) UserFlairWithID

func (c *Reddit) UserFlairWithID(name, user, text string) error

UserFlairWithID is the same as UserFlair but explicit redditor name.

type RedditErr

type RedditErr struct {
	Message string `json:"message"`
	Error   string `json:"error"`
}

RedditErr is a struct to store reddit error messages.

type RedditVals

type RedditVals struct {
	GetSubmissionFromCommentTries int
}

RedditVals is just some values to backoff

type Streaming

type Streaming struct {
	CommentListInterval time.Duration
	PostListInterval    time.Duration
	PostListSlice       int
}

Streaming is used for some durations on how frequently do we listen to comments/submissions

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL