Skip to content

Instantly share code, notes, and snippets.

@alphaKAI
Created December 3, 2014 09:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alphaKAI/c7253e83da01a63d9c30 to your computer and use it in GitHub Desktop.
Save alphaKAI/c7253e83da01a63d9c30 to your computer and use it in GitHub Desktop.
Tweet only Twitter Client. use: Twitter4d, GtkD build : $ dmd gtkTweet.d twitter4d.d -L-lcurl -L-lgtkd-2 -L-ldl

gtkTweet

Requirements

  • dmd : v2.066
  • gtkd : latest Version

Build

  1. clone this gist
  2. $ git clone https://github.com/alphaKAI/twitter4d && cp twitter4d/source/twitter4d.d .
  3. configure "setting.json"
  4. $ dmd gtkTweet.d twitter4d.d -L-lcurl -L-lgtkd-2 -L-ldl
  5. ./gtkTweet Enjoy!
import gtk.MainWindow,
gtk.Button,
gtk.Widget,
gtk.Label,
gtk.Entry,
gtk.Main,
gtk.VBox,
gtk.HBox;
import core.thread;
import twitter4d;
class Tweet{
import std.net.curl,
std.string,
std.regex,
std.stdio,
std.file,
std.conv,
std.json;
private Twitter4D t4d;
this(){
string jsonString = readSettingFile;
auto parsed = parseJSON(jsonString);
t4d = new Twitter4D([
"consumerKey" : getJsonData(parsed, "consumerKey"),
"consumerSecret" : getJsonData(parsed, "consumerSecret"),
"accessToken" : getJsonData(parsed, "accessToken"),
"accessTokenSecret" : getJsonData(parsed, "accessTokenSecret")]);
}
bool tweet(string tweetString){
if(tweetString.length == 0)
return false;
t4d.request("POST", "statuses/update.json", ["status" : tweetString]);
return true;
}
string getAccountName(){
return getJsonData(parseJSON(t4d.request("GET", "account/verify_credentials.json", ["":""])), "screen_name");
}
private{
string readSettingFile(){
string settingFilePath = "setting.json";
if(!exists(settingFilePath))
throw new Error("Please create file of setting.json and configure your consumer & access tokens");
auto file = File(settingFilePath, "r");
string buf;
foreach(line; file.byLine)
buf = buf ~ cast(string)line;
return buf;
}
string getJsonData(JSONValue parsedJson, string key){
return parsedJson.object[key].to!string.replace(regex("\"", "g") ,"");
}
}
}
class GtkTweet{
Tweet twitter;
this(){
twitter = new Tweet;
/*+ Thread guiThread = new Thread(&guiMain);
guiThread.start;
guiThread.join;*/
guiMain;
}
void guiMain(){
string[] opt;
Main.init(opt);
// Define
MainWindow mainWindow = new MainWindow("DTweet");
Label topString = new Label("What are you doing?"),
account = new Label(""),
status = new Label("status : ready"),
lastTweet = new Label("last : ");
VBox vbox = new VBox(false, 5);
HBox hbox = new HBox(false, 5);
Button send = new Button("send!"),
clear = new Button("clear");
Entry textfield = new Entry;
// Configure
mainWindow.addOnDestroy(((Widget w) => Main.quit));
mainWindow.setDefaultSize(400, 100);
send.addOnClicked((Button b){
string text = textfield.getText;
status.setText("sending...");
textfield.setText("");
if(twitter.tweet(text)){
status.setText("status : Success");
lastTweet.setText(text);
} else {
status.setText("status : Fail");
textfield.setText("last : " ~ text);
}
});
clear.addOnClicked((Button b){
textfield.setText("");
});
account.setText("Account : @" ~ twitter.getAccountName);
// adding
mainWindow.add(vbox);
foreach(e; [topString, account])
vbox.add(e);
vbox.add(textfield);
vbox.add(hbox);
vbox.add(textfield);
vbox.add(hbox);
hbox.add(send);
hbox.add(clear);
foreach(e; [status, lastTweet])
vbox.add(e);
mainWindow.showAll;
Main.run;
}
}
void main(){
new GtkTweet;
}
{
"consumerKey" : "",
"consumerSecret" : "",
"accessToken" : "",
"accessTokenSecret" : ""
}
/*
The Simple Twitter API Wrapper For D Programming Language.
Copyright (C) alphaKAI 2014 http://alpha-kai-net.info
THE MIT LICENSE.
*/
import std.digest.sha,
std.algorithm,
std.datetime,
std.net.curl,
std.base64,
std.format,
std.string,
std.array,
std.regex,
std.stdio,
std.json,
std.conv;
class Twitter4D{
private{
string consumerKey,
consumerSecret,
accessToken,
accessTokenSecret;
string baseUrl = "https://api.twitter.com/1.1/";
}
this(string[string] oauthHash){
if(oauthHash.length < 4)
throw new Error("Error: When Initialize this class, requirements 4 element");
consumerKey = oauthHash["consumerKey"];
consumerSecret = oauthHash["consumerSecret"];
accessToken = oauthHash["accessToken"];
accessTokenSecret = oauthHash["accessTokenSecret"];
}
this(string consumerKey, string consumerSecret,
string accessToken, string accessTokenSecret){
this.consumerKey = consumerKey;
this.consumerSecret = consumerSecret;
this.accessToken = accessToken;
this.accessTokenSecret = accessTokenSecret;
}
// post/get request function
// Ex: request("POST", "statuses/update.json" ["status": "hoge"]);
auto request(string type, string endPoint, string[string] paramsArgument = ["":""]){
string method = (){
if(type == "get" || type == "GET")
return "GET";
else if(type == "post" || type == "POST")
return "POST";
else
throw new Error("Method Name Error");
}();
string[string] params = buildParams(paramsArgument);
string url = baseUrl ~ endPoint;
string oauthSignature = signature(consumerSecret, accessTokenSecret, method, url, params);
params["oauth_signature"] = oauthSignature;
auto authorizeKeys = params.keys.filter!q{a.countUntil("oauth_")==0};
auto authorize = "OAuth " ~ authorizeKeys.map!(k => k ~ "=" ~ params[k]).join(",");
string path = params.keys.map!(k => k ~ "=" ~ params[k]).join("&");
auto http = HTTP();
http.addRequestHeader("Authorization", authorize);
if(method == "GET")
return get(url ~ "?" ~ path, http);
else if(method == "POST")
return post(url, path, http);
return null;
}
//Testing
auto stream(string url = "https://userstream.twitter.com/1.1/user.json"){
string[string] params = buildParams();
string oauthSignature = signature(consumerSecret, accessTokenSecret, "GET", url, params);
params["oauth_signature"] = oauthSignature;
auto authorizeKeys = params.keys.filter!q{a.countUntil("oauth_")==0};
auto authorize = "OAuth " ~ authorizeKeys.map!(k => k ~ "=" ~ params[k]).join(",");
string path = params.keys.map!(k => k ~ "=" ~ params[k]).join("&");
auto http = HTTP();
http.addRequestHeader("Authorization", authorize);
http.method = HTTP.Method.get;
auto streamSocket = byLineAsync(url ~ "?" ~ path);
return streamSocket;
}
private{
string hexconv(T)(T s){
auto t = appender!string();
formattedWrite(t, "%x", s);
return '%' ~ t.data;
}
bool isMark(string str){
string charset = "abcdefghijklmnopqrstuvwxyz";
foreach(e; charset)
charset ~= toUpper(e);
charset ~= "1234567890._-";
foreach(x; str)
foreach(y; charset)
if(x == y)
return false;
return true;
}
string urlEncode(string urlString){
string array[];
array.length = urlString.length;
foreach(i, charc; urlString){
if(isMark(charc.to!string))
array[i] = toUpper(hexconv(charc));
else
array[i] = charc.to!string;
}
return array.join();
}
string urlEncodAndJoinWithPattern(string[] array, string pattern){
foreach(ref e; array)
e = urlEncode(e);
return array.join(pattern);
}
string[string] buildParams(string[string] additionalParam = ["":""]){
string now = Clock.currTime.toUnixTime.to!string;
string[string] params = [
"oauth_consumer_key" : consumerKey,
"oauth_nonce" : "4324yfe",
"oauth_signature_method" : "HMAC-SHA1",
"oauth_timestamp" : now,
"oauth_token" : accessToken,
"oauth_version" : "1.0"];
if(additionalParam != ["":""])
foreach(key, value; additionalParam)
params[key] = value;
foreach(key, value; params)
params[key] = urlEncode(value);
return params;
}
ubyte[] hmac_sha1(in string key, in string message){
auto padding(in ubyte[] k){
auto h = (64 < k.length)? sha1Of(k): k;
return h ~ new ubyte[64 - h.length];
}
const k = padding(cast(ubyte[])key);
return sha1Of((k.map!q{cast(ubyte)(a^0x5c)}.array) ~ sha1Of((k.map!q{cast(ubyte)(a^0x36)}.array) ~ cast(ubyte[])message)).dup;
}
string signature(string consumerSecret, string accessTokenSecret, string method, string url, string[string] params){
auto query = params.keys.sort.map!(k => k ~ "=" ~ params[k]).join("&");
auto key = urlEncodAndJoinWithPattern([consumerSecret, accessTokenSecret], "&");
auto base = urlEncodAndJoinWithPattern([method, url, query], "&");
string oauthSignature = urlEncode(Base64.encode(hmac_sha1(key, base)));
return oauthSignature;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment