new quote subcommand
This commit is contained in:
parent
cba6e63238
commit
d3632b9b4a
10
Readme.md
10
Readme.md
|
@ -2,7 +2,7 @@ drivel
|
||||||
========
|
========
|
||||||
|
|
||||||
drivel is a Twitter command line interface for status updates, media upload,
|
drivel is a Twitter command line interface for status updates, media upload,
|
||||||
your home timeline, your mention timeline, replies and likes.
|
your home timeline, your mention timeline, replies, quotes and likes.
|
||||||
My personal opinion is that you shouldn't be on Twitter in the first place, but
|
My personal opinion is that you shouldn't be on Twitter in the first place, but
|
||||||
anyway...
|
anyway...
|
||||||
|
|
||||||
|
@ -47,13 +47,19 @@ To update your status with optional media upload...
|
||||||
drivel status STATUS [FILE1, FILE2, ...]
|
drivel status STATUS [FILE1, FILE2, ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
...or reply to a tweet with a specific ID:
|
...reply to a tweet with a specific ID...
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
drivel reply TWEET_ID MESSAGE [FILE1, FILE2, ...]
|
drivel reply TWEET_ID MESSAGE [FILE1, FILE2, ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
...or quote a tweet with a specific ID...
|
||||||
|
|
||||||
|
```
|
||||||
|
drivel quote TWEET_ID MESSAGE [FILE1, FILE2, ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
with any number of files, as long as they are .jpg, .png, .gif or .mp4 and smaller than 50 MB each. On first use, drivel will ask you to go to [https://apps.twitter.com/app/new](https://apps.twitter.com/app/new), register a new app and create an access token. Those values will be stored in HOME/.drivel/ for later use.
|
with any number of files, as long as they are .jpg, .png, .gif or .mp4 and smaller than 50 MB each. On first use, drivel will ask you to go to [https://apps.twitter.com/app/new](https://apps.twitter.com/app/new), register a new app and create an access token. Those values will be stored in HOME/.drivel/ for later use.
|
||||||
|
|
||||||
|
|
52
drivel.go
52
drivel.go
|
@ -24,6 +24,7 @@ const (
|
||||||
STATUS_ENDPOINT = "https://api.twitter.com/1.1/statuses/update.json"
|
STATUS_ENDPOINT = "https://api.twitter.com/1.1/statuses/update.json"
|
||||||
MENTIONS_ENDPOINT = "https://api.twitter.com/1.1/statuses/mentions_timeline.json?tweet_mode=extended&count=200"
|
MENTIONS_ENDPOINT = "https://api.twitter.com/1.1/statuses/mentions_timeline.json?tweet_mode=extended&count=200"
|
||||||
HOME_ENDPOINT = "https://api.twitter.com/1.1/statuses/home_timeline.json?tweet_mode=extended&count=200"
|
HOME_ENDPOINT = "https://api.twitter.com/1.1/statuses/home_timeline.json?tweet_mode=extended&count=200"
|
||||||
|
LOOKUP_ENDPOINT = "https://api.twitter.com/1.1/statuses/lookup.json?tweet_mode=extended"
|
||||||
LIKE_ENDPOINT = "https://api.twitter.com/1.1/favorites/create.json"
|
LIKE_ENDPOINT = "https://api.twitter.com/1.1/favorites/create.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -101,14 +102,14 @@ type ProcessingInfo struct {
|
||||||
Error TwitterError
|
Error TwitterError
|
||||||
}
|
}
|
||||||
|
|
||||||
type PollStatusResponse struct {
|
|
||||||
Processing_info ProcessingInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func PollStatusParameters(mediaID ObjectID) string {
|
func PollStatusParameters(mediaID ObjectID) string {
|
||||||
return "?command=STATUS&media_id=" + string(mediaID)
|
return "?command=STATUS&media_id=" + string(mediaID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PollStatusResponse struct {
|
||||||
|
Processing_info ProcessingInfo
|
||||||
|
}
|
||||||
|
|
||||||
func UpdateStatusRequest(status string, mediaIDs []ObjectID, previousStatusID ObjectID) url.Values {
|
func UpdateStatusRequest(status string, mediaIDs []ObjectID, previousStatusID ObjectID) url.Values {
|
||||||
r := map[string][]string{"status": {status}}
|
r := map[string][]string{"status": {status}}
|
||||||
if len(mediaIDs) > 0 {
|
if len(mediaIDs) > 0 {
|
||||||
|
@ -130,6 +131,10 @@ type UpdateStatusResponse struct {
|
||||||
Id_str string
|
Id_str string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LookupParameters(ids []string) string {
|
||||||
|
return "&id=" + strings.Join(ids, ",")
|
||||||
|
}
|
||||||
|
|
||||||
var mimetype = map[string]string{
|
var mimetype = map[string]string{
|
||||||
".mp4": "video/mp4",
|
".mp4": "video/mp4",
|
||||||
".jpg": "image/jpeg",
|
".jpg": "image/jpeg",
|
||||||
|
@ -465,14 +470,21 @@ func (d *data) push(client *http.Client, previous ObjectID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateStatus(args []string, previous ObjectID) {
|
func updateStatus(args []string, previous ObjectID, embedTweet ObjectID) {
|
||||||
d := splitArguments(args)
|
d := splitArguments(args)
|
||||||
httpClient := getClient()
|
httpClient := getClient()
|
||||||
|
if embedTweet != "" {
|
||||||
|
tweets := lookup(httpClient, []string{string(embedTweet)})
|
||||||
|
if len(tweets) == 1 {
|
||||||
|
d.status[0] += " " + tweets[0].URL()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d.push(httpClient, previous)
|
d.push(httpClient, previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
func status(args []string) error {
|
func status(args []string) error {
|
||||||
updateStatus(args, "")
|
updateStatus(args, "", "")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +493,16 @@ func reply(args []string) error {
|
||||||
fmt.Fprintln(os.Stderr, "Usage: drivel reply TWEET_ID MESSAGE [FILE1, FILE2, ...]")
|
fmt.Fprintln(os.Stderr, "Usage: drivel reply TWEET_ID MESSAGE [FILE1, FILE2, ...]")
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
updateStatus(args[1:], ObjectID(args[0]))
|
updateStatus(args[1:], ObjectID(args[0]), "")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func quote(args []string) error {
|
||||||
|
if len(args) < 2 {
|
||||||
|
fmt.Println(os.Stderr, "Usage: drivel quote TWEET_ID MESSAGE [FILE1, FILE2, ...]")
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
updateStatus(args[1:], "", ObjectID(args[0]))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,8 +516,22 @@ func (m Status) String() string {
|
||||||
return m.User.Name + " " + "(" + m.Id_str + ")" + ":\n" + m.Full_text
|
return m.User.Name + " " + "(" + m.Id_str + ")" + ":\n" + m.Full_text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Status) URL() string {
|
||||||
|
return "https://twitter.com/" + m.User.Screen_name + "/status/" + m.Id_str
|
||||||
|
}
|
||||||
|
|
||||||
type StatusUser struct {
|
type StatusUser struct {
|
||||||
Name string
|
Name string
|
||||||
|
Screen_name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookup(client *http.Client, ids []string) []Status {
|
||||||
|
log := func(err error) { optLogFatal("lookup "+strings.Join(ids, ","), err) }
|
||||||
|
body := get(client, LOOKUP_ENDPOINT+LookupParameters(ids))
|
||||||
|
var tweets []Status
|
||||||
|
err := json.Unmarshal(body, &tweets)
|
||||||
|
log(err)
|
||||||
|
return tweets
|
||||||
}
|
}
|
||||||
|
|
||||||
func timeline(endpoint string) {
|
func timeline(endpoint string) {
|
||||||
|
@ -550,6 +585,7 @@ func main() {
|
||||||
goutil.NewCommand("home", home, "get your home timeline"),
|
goutil.NewCommand("home", home, "get your home timeline"),
|
||||||
goutil.NewCommand("mentions", mentions, "get your mention timeline"),
|
goutil.NewCommand("mentions", mentions, "get your mention timeline"),
|
||||||
goutil.NewCommand("reply", reply, "reply to a tweet with a specific ID"),
|
goutil.NewCommand("reply", reply, "reply to a tweet with a specific ID"),
|
||||||
|
goutil.NewCommand("quote", quote, "quote retweet a tweet with a specific ID"),
|
||||||
goutil.NewCommand("like", like, "like a tweet with a specific ID"),
|
goutil.NewCommand("like", like, "like a tweet with a specific ID"),
|
||||||
}
|
}
|
||||||
err := goutil.Execute(commands)
|
err := goutil.Execute(commands)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user