The fantastic Reddit API wrapper for gophers

Overview

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.Info("t2_...")
	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
}
Issues
  • Can you go to the next page?

    Can you go to the next page?

    Hi I can't figure out how to go to the next page, it only prints the first one. I also tried without separating the id from the identifier (eg. d7gsv instead of t3_d7gsv). I would also like to know if there's a way to sort these by newest. I only saw Submissions() having a sort argument not SubmissionsAfter(). This is my code

    var lastPostId string
    
    // Initialize a new mira instance
    r, err := mira.Init(creds)
    if err != nil {
    	log.Fatal(err)
    }	
    
    if rippingType == "r" {
    	postCount := 1
    	for {
    		subsAfter, err := r.Subreddit(rippingIdentifier).SubmissionsAfter(lastPostId, 100)
    		if err != nil {
    			log.Printf("Failed to fetch /%s/%s: %v\n", rippingType, rippingIdentifier, err)
    		}
    
    		// Define an output folder and print out a message
    		rippingIdentifier = subsAfter[0].GetSubreddit()
    		if !isOutputUserDefined {
    			outputFolder = "rips/reddit_sub_" + rippingIdentifier + "/"
    		}
    		colorstring.Printf("[green]Ripping /%s/%s // Output folder: %s\n", rippingType, rippingIdentifier, outputFolder)
    
    		// Iterate over each page
    		for _, v := range subsAfter {
    			fmt.Printf("[%d] [/%s/%s] %s // Downloading: %s\n", postCount, rippingType, rippingIdentifier, v.GetId(), v.GetUrl())
    			lastPostId = strings.Split(v.GetId(), "_")[1]
    			postCount ++
    		}
    	}		
    }
    
    opened by electrooz 5
  • Can you use Mira to view a user profile?

    Can you use Mira to view a user profile?

    For example, if I wanted to automatically stream new comments made by my account to a file on local disc, is there a way to "stream" those comments, similar to how the subreddit listener serves new posts?

    opened by WadeLewis 3
  • Panic: runtime error: invalid memory address or nil pointer dereference

    Panic: runtime error: invalid memory address or nil pointer dereference

    Hi!

    I´m getting this error running this code example.

    package main
    
    import (
    	"fmt"
    
    	"github.com/thecsw/mira"
    )
    
    func main() {
    	x := mira.Credentials{ClientId: "*", ClientSecret: "*", Username: "*", Password: "*", UserAgent: "*"}
    	r, _ := mira.Init(x)
    	sort := "top"
    	var limit int = 25
    	duration := "all"
    	subs, _ := r.Subreddit("all").Submissions(sort, duration, limit)
    	for _, v := range subs {
    		fmt.Println("Submission Title: ", v.GetTitle())
    	}
    }
    

    Error:

    [signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0x2e358e]
    
    goroutine 1 [running]:
    github.com/thecsw/mira.(*Reddit).addQueue(...)
    	/tmp/gopath892572453/pkg/mod/github.com/thecsw/[email protected]+incompatible/reddit.go:624
    github.com/thecsw/mira.(*Reddit).Subreddit(...)
    	/tmp/gopath892572453/pkg/mod/github.com/thecsw/[email protected]+incompatible/reddit.go:50
    main.main()
    	/tmp/sandbox199244126/prog.go:15 +0x10e
    

    Sure i placed my login info right but getting the same error on 2 of my devices and on play.golang.org. I´m definitely not an go expret so don´t know if there is an easy fix?

    opened by AlexLab 2
  • Adding support for subreddit reports and mod queues

    Adding support for subreddit reports and mod queues

    Added reports and mod queue fetching with streaming support. Took the liberty to remove ReportReasons (reddit API's report_reasons) as it always returns "This attribute is deprecated. Please use mod_reports and user_reports instead." now.

    enhancement 
    opened by devmedoo 1
  • check for OOB read in getSubmission/getComment

    check for OOB read in getSubmission/getComment

    Hey,

    I noticed that mira panics when trying to r.Submission("t3_asdf12").Info() when t3_asdf12 is an invalid/unknown id, since the json returned is empty. I added a simple check that throws an error that can easily be caught in the app using mira.

    Greetings, u/try_to_guess_my_psn

    opened by ttgmpsn 1
  • Bump go CI version to 1.17, delete travis and gopkg

    Bump go CI version to 1.17, delete travis and gopkg

    When I wrote mira about 3-4 years ago, I used travis for CI and cloud testing, this was before Github Actions was a thing. This is mostly a maintenance PR to delete old dependencies and freshen up the version here a little bit. Recall that mira was written in Go 1.13

    Signed-off-by: Sandy Urazayev [email protected]

    enhancement 
    opened by thecsw 0
  • Streaming comments stops working...

    Streaming comments stops working...

    Hi there.

    When using the library's streaming comments capability:

    comments, err := r.Subreddit("aww").StreamComments()
    if err != nil {
    	log.Println(err)
    }
    

    It will work for awhile (usually 10-20 minutes), but then just stop streaming new comments, even on very active subreddits. There are no errors being returned as far as I can tell. Has anyone else experienced this issue?

    opened by tildewtf 2
  • Streaming without login

    Streaming without login

    Is there a possibility to stream submissions without login credentials? Since I dont want to post and only want to stream submissions of a subreddit, which should be doable via the public API this should be doable without login credentials

    opened by DarkWingMcQuack 1
Releases(v4.0.0)
  • v4.0.0(Mar 27, 2020)

    The problem

    mira was mostly a home-cooked product for some internal Reddit API uses within Stellom. Bad fixes and middle-of-the-night typo fixing caused this bad habit of rapid releasing and sometimes making breaking changes to the API.

    The solution

    v4.0.0. should be considered a stable public release, mira is working well and doesn't require any new hotfixes and can be easily extended to any special cases or unimplemented Reddit endpoints. Please feel free to use mira. Any new changes should not be breaking in v4.X.X

    Thank you

    Source code(tar.gz)
    Source code(zip)
  • v2.5.3(Sep 22, 2019)

  • v2.5.2(Sep 15, 2019)

  • v2.5.1(Sep 2, 2019)

  • v2.5.0(Aug 31, 2019)

  • v2.2.0(Jul 31, 2019)

  • v2.0.0(Jul 29, 2019)

    New mira release includes better interfaces and chainable functions!

    You can do new tricks, like:

    r.Subreddit("mysubreddit").Submit("mytitle", "mytext")

    And other cool stuff. For more information, please refer to the README.md

    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Jul 27, 2019)

  • v1.1.1(Jul 21, 2019)

  • v1.1.0(Jul 15, 2019)

    This new release includes improvements for mira, such as custom *http.Client handlers you can give, special request method for mira requests, various improvements, and better error handling.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jul 8, 2019)

    This is first release of mira. It's stable, it's working. We have some things going for mira as passing custom http.Client objects, better structuring, etc.

    Thanks.

    Source code(tar.gz)
    Source code(zip)
Owner
Sandy
¯\_(ツ)_/¯
Sandy
JSON API for a random meme scraped from reddit.

JSON API for a random meme scraped from reddit.

Catuserbot 0 Feb 11, 2022
Nvote - Decentralized, vote-driven community similar to services like Reddit and HackerNews. Built on nostr

NVote Nvote is a decentralized, vote-driven community similar to services like R

Ronald Bell 14 May 8, 2022
The NVD API is an unofficial Go wrapper around the NVD API.

NVD API The NVD API is an unofficial Go wrapper around the NVD API. Supports: CVE CPE How to use The following shows how to basically use the wrapper

Lucas TESSON 3 May 9, 2022
A Wrapper Client for Google Spreadsheet API (Sheets API)

Senmai A Wrapper Client for Google Spreadsheet API (Sheets API) PREPARATION Service Account and Key File Create a service account on Google Cloud Plat

ytnobody / satoshi azuma 0 Nov 5, 2021
A GoLang wrapper for Politics & War's API. Forego the hassle of accessing the API directly!

A GoLang wrapper for Politics & War's API. Forego the hassle of accessing the API directly!

null 1 Mar 5, 2022
Simple golang airtable API wrapper

Golang Airtable API A simple #golang package to access the Airtable API. Table of contents Golang Airtable API Table of contents Installation Basic us

mehanizm 37 Mar 21, 2022
This is a Golang wrapper for working with TMDb API. It aims to support version 3.

This is a Golang wrapper for working with TMDb API. It aims to support version 3. An API Key is required. To register for one, head over to themoviedb

Cyro Dubeux 52 May 18, 2022
⚡️ SharePoint authentication, HTTP client & fluent API wrapper for Go (Golang)

Gosip - SharePoint authentication, HTTP client & fluent API wrapper for Go (Golang) Main features Unattended authentication using different strategies

Andrew Koltyakov 73 May 10, 2022
Trello API wrapper for Go

Go Trello API A #golang package to access the Trello API. Nearly 100% of the read-only surface area of the API is covered, as is creation and modifica

Aaron Longwell 199 Apr 13, 2022
null 86 May 3, 2022
A small, fast, reliable pastemyst API wrapper written in Golang

A small, fast, reliable pastemyst API wrapper written in Golang. Official pastemyst API docs found here.

null 11 Nov 18, 2021
SpamProtection-Go is an Official golang wrapper for Intellivoid SpamProtection API

SpamProtection-Go is an Official golang wrapper for Intellivoid SpamProtection API, which is fast, secure and requires no additional packages to be installed.

Intellivoid 0 Feb 26, 2022
A Telegraph API wrapper in Go

Telegra.ph is a minimalist publishing tool that allows you to create richly formatted posts and push them to the Web in just a click. Telegraph posts also get beautiful Instant View pages on Telegram. So, this Go wrapper enables you to do all that easily.

Anony 23 May 16, 2022
Unofficial Anilist.co GraphQL API wrapper for GoLang.

anilistWrapGo Unofficial Anilist.co GraphQL API wrapper for GoLang. Examples All examples are present as tests in test directory. Below are a few snip

ダンクデル (Sayan Biswas) 14 Feb 17, 2022
Pterodactyl API wrapper written in Golang

WARNING That repository isn't available for production environment. Many endpoints aren't yet implemented. Be careful if you are using that module. pt

Luiz Otávio de Farias Correa 3 Mar 28, 2022
💻 Quotable.io API Wrapper + CLI App

?? Quotable.io API Wrapper + CLI App

Eliaz Bobadilla 9 Apr 9, 2022
A Wrapper of the Piston API in Golang

Go-Piston! This is a Go wrapper for working with the Piston API. It supports both the endpoints, namely runtimes and execute, mentioned here. ?? Insta

null 7 Feb 20, 2022
Golang wrapper for the FiveM natives API

Golang wrapper for the FiveM natives API

normalM 3 Nov 20, 2021
spamwatch-go is official Go wrapper for SpamWatch API

SpamWatch API Go Wrapper spamwatch-go is official Go wrapper for SpamWatch API, which is fast, secure and requires no additional packages to be instal

SpamWatch 7 Feb 17, 2022