Beispiel #1
0
 /**
  * Use cursors to fetch upto jtwit.maxResults TODO More controlled paging??
  *
  * @param url API method to call
  * @param screenName
  * @param userId
  * @return twitter-id numbers for friends/followers of screenName or userId Is affected by {@link
  *     #maxResults}
  */
 private List<Number> getUserIDs(String url, String screenName, Long userId) {
   Long cursor = -1L;
   List<Number> ids = new ArrayList<Number>();
   if (screenName != null && userId != null)
     throw new IllegalArgumentException(
         "cannot use both screen_name and user_id when fetching user_ids");
   Map<String, String> vars = InternalUtils.asMap("screen_name", screenName, "user_id", userId);
   while (cursor != 0 && !jtwit.enoughResults(ids)) {
     vars.put("cursor", String.valueOf(cursor));
     String json = http.getPage(url, vars, http.canAuthenticate());
     try {
       // it seems Twitter will occasionally return a raw array
       JSONArray jarr;
       if (json.charAt(0) == '[') {
         jarr = new JSONArray(json);
         cursor = 0L;
       } else {
         JSONObject jobj = new JSONObject(json);
         jarr = (JSONArray) jobj.get("ids");
         cursor = new Long(jobj.getString("next_cursor"));
       }
       for (int i = 0; i < jarr.length(); i++) {
         ids.add(jarr.getLong(i));
       }
       if (jarr.length() == 0) {
         // No more
         break;
       }
     } catch (JSONException e) {
       throw new TwitterException.Parsing(json, e);
     }
   }
   return ids;
 }
Beispiel #2
0
 /**
  * Returns information of a given user, specified by user-id.
  *
  * @param userId The user-id of a user.
  * @throws exception if the user does not exist - or has been terminated (as happens to spam
  *     bots).
  */
 public User show(Number userId) {
   Map<String, String> vars = InternalUtils.asMap("user_id", userId.toString());
   String json =
       http.getPage(jtwit.TWITTER_URL + "/users/show.json", vars, http.canAuthenticate());
   try {
     User user = new User(new JSONObject(json), null);
     return user;
   } catch (JSONException e) {
     throw new TwitterException.Parsing(json, e);
   }
 }
Beispiel #3
0
 /**
  * @return true if followerScreenName <i>is</i> following followedScreenName
  * @throws TwitterException.E403 if one of the users has protected their updates and you don't
  *     have access. This can be counter-intuitive (and annoying) at times! Also throws E403 if one
  *     of the users has been suspended (we use the {@link SuspendedUser} exception sub-class for
  *     this).
  * @throws TwitterException.E404 if one of the users does not exist
  */
 public boolean isFollower(String followerScreenName, String followedScreenName) {
   assert followerScreenName != null && followedScreenName != null;
   try {
     Map vars =
         InternalUtils.asMap(
             "source_screen_name", followerScreenName,
             "target_screen_name", followedScreenName);
     String page =
         http.getPage(jtwit.TWITTER_URL + "/friendships/show.json", vars, http.canAuthenticate());
     JSONObject jo = new JSONObject(page);
     JSONObject trgt = jo.getJSONObject("relationship").getJSONObject("target");
     boolean fby = trgt.getBoolean("followed_by");
     return fby;
   } catch (TwitterException.E403 e) {
     if (e instanceof SuspendedUser) throw e;
     // Should this be a suspended user exception instead?
     // Let's ask Twitter
     // TODO check rate limits - only do if we have spare capacity
     String whoFirst =
         followedScreenName.equals(jtwit.getScreenName())
             ? followerScreenName
             : followedScreenName;
     try {
       // this could throw a SuspendedUser exception
       show(whoFirst);
       String whoSecond =
           whoFirst.equals(followedScreenName) ? followerScreenName : followedScreenName;
       if (whoSecond.equals(jtwit.getScreenName())) throw e;
       show(whoSecond);
     } catch (TwitterException.RateLimit e2) {
       // ignore
     }
     // both shows worked?
     throw e;
   } catch (TwitterException e) {
     // FIXME investigating a weird new bug
     if (e.getMessage() != null
         && e.getMessage().contains("Two user ids or screen_names must be supplied"))
       throw new TwitterException(
           "WTF? inputs: follower="
               + followerScreenName
               + ", followed="
               + followedScreenName
               + ", call-by="
               + jtwit.getScreenName()
               + "; "
               + e.getMessage());
     throw e;
   }
 }
Beispiel #4
0
 /**
  * Common backend for {@link #bulkShow(List)} and {@link #bulkShowById(List)}. Works in batches of
  * 100.
  *
  * <p>This will throw exceptions from the 1st page of results, but swallow them from subsequent
  * pages (which are likely to be rate limit errors).
  *
  * <p>Suspended bot accounts seem to just get ignored.
  *
  * @param stringOrNumber
  * @param screenNamesOrIds
  */
 List<User> bulkShow2(String apiMethod, Class stringOrNumber, Collection screenNamesOrIds) {
   // Requires authentication in v1.1, though not in 1 which is still usable
   boolean auth = InternalUtils.authoriseIn11(jtwit);
   int batchSize = 100;
   ArrayList<User> users = new ArrayList<User>(screenNamesOrIds.size());
   List _screenNamesOrIds =
       screenNamesOrIds instanceof List
           ? (List) screenNamesOrIds
           : new ArrayList(screenNamesOrIds);
   for (int i = 0; i < _screenNamesOrIds.size(); i += batchSize) {
     int last = i + batchSize;
     String names = InternalUtils.join(_screenNamesOrIds, i, last);
     String var = stringOrNumber == String.class ? "screen_name" : "user_id";
     Map<String, String> vars = InternalUtils.asMap(var, names);
     try {
       String json = http.getPage(jtwit.TWITTER_URL + apiMethod, vars, auth);
       List<User> usersi = User.getUsers(json);
       users.addAll(usersi);
     } catch (TwitterException.E404 e) {
       // All names were bogus or deleted users!
       // Oh well
     } catch (TwitterException e) {
       // Stop here.
       // Don't normally throw an exception so we don't waste the
       // results we have.
       if (users.size() == 0) throw e;
       e.printStackTrace();
       break;
     }
   }
   return users;
 }
Beispiel #5
0
 /**
  * Start following a user.
  *
  * @param username Required. The ID or screen name of the user to befriend.
  * @return The befriended user, or null if (a) they were already being followed, or (b) they
  *     protect their tweets & you already requested to follow them.
  * @throws TwitterException if the user does not exist or has been suspended.
  * @see #stopFollowing(String)
  */
 public User follow(String username) throws TwitterException {
   if (username == null) throw new NullPointerException();
   if (username.equals(jtwit.getScreenName()))
     throw new IllegalArgumentException("follow yourself makes no sense");
   String page = null;
   try {
     Map<String, String> vars = InternalUtils.asMap("screen_name", username);
     page = http.post(jtwit.TWITTER_URL + "/friendships/create.json", vars, true);
     // is this needed? doesn't seem to fix things
     // http.getPage(jtwit.TWITTER_URL+"/friends", null, true);
     return new User(new JSONObject(page), null);
   } catch (SuspendedUser e) {
     throw e;
   } catch (TwitterException.Repetition e) {
     return null;
   } catch (E403 e) {
     // check if we've tried to follow someone we're already following
     try {
       if (isFollowing(username)) return null;
     } catch (TwitterException e2) {
       // no extra info then
     }
     throw e;
   } catch (JSONException e) {
     throw new TwitterException.Parsing(page, e);
   }
 }
Beispiel #6
0
 /**
  * Low-level method for fetching e.g. your friends
  *
  * @param url
  * @param screenName e.g. your screen-name
  * @return
  */
 private List<User> getUsers(String url, String screenName) {
   Map<String, String> vars = InternalUtils.asMap("screen_name", screenName);
   List<User> users = new ArrayList<User>();
   Long cursor = -1L;
   while (cursor != 0 && !jtwit.enoughResults(users)) {
     vars.put("cursor", cursor.toString());
     JSONObject jobj;
     try {
       jobj = new JSONObject(http.getPage(url, vars, http.canAuthenticate()));
       users.addAll(User.getUsers(jobj.getString("users")));
       cursor = new Long(jobj.getString("next_cursor"));
     } catch (JSONException e) {
       throw new TwitterException.Parsing(null, e);
     }
   }
   return users;
 }
Beispiel #7
0
 /**
  * Enables notifications for updates from the specified user <i>who must already be a friend</i>.
  *
  * @param username Get notifications from this user, who must already be one of your friends.
  * @return the specified user
  */
 public User notify(String username) {
   Map<String, String> vars = InternalUtils.asMap("screen_name", username);
   String page = http.getPage(jtwit.TWITTER_URL + "/notifications/follow.json", vars, true);
   try {
     return new User(new JSONObject(page), null);
   } catch (JSONException e) {
     throw new TwitterException.Parsing(page, e);
   }
 }
Beispiel #8
0
 /**
  * blocks/destroy: Un-blocks screenName for the authenticating user. Returns the un-blocked user
  * when successful. If relationships existed before the block was instated, they will not be
  * restored.
  *
  * @param screenName
  * @return the now un-blocked User
  * @see #block(String)
  */
 public User unblock(String screenName) {
   HashMap vars = new HashMap();
   vars.put("screen_name", screenName);
   // Returns if the authenticating user is blocking a target user.
   // Will return the blocked user's object if a block exists, and error
   // with
   // a HTTP 404 response code otherwise.
   String json = http.post(jtwit.TWITTER_URL + "/blocks/destroy.json", vars, true);
   return InternalUtils.user(json);
 }
Beispiel #9
0
 /**
  * @param truncatedStatus If this is a twitlonger.com truncated status, then call twitlonger to
  *     fetch the full text.
  * @return the full status message. If this is not a twitlonger status, this will just return the
  *     status text as-is.
  * @see #updateLongStatus(String, long)
  */
 public String getLongStatus(Status truncatedStatus) {
   // regex for http://tl.gd/ID
   int i = truncatedStatus.text.indexOf("http://tl.gd/");
   if (i == -1) return truncatedStatus.text;
   String id = truncatedStatus.text.substring(i + 13).trim();
   String response = http.getPage("http://www.twitlonger.com/api_read/" + id, null, false);
   Matcher m = contentTag.matcher(response);
   boolean ok = m.find();
   if (!ok) throw new TwitterException.TwitLongerException("TwitLonger call failed", response);
   String longMsg = m.group(1).trim();
   return longMsg;
 }
Beispiel #10
0
 /**
  * Returns information of a given user, specified by screen name.
  *
  * @param screenName The screen name of a user.
  * @throws exception if the user does not exist
  * @throws SuspendedUser if the user has been terminated (as happens to spam bots).
  * @see #show(long)
  */
 public User show(String screenName) throws TwitterException, TwitterException.SuspendedUser {
   Map vars = InternalUtils.asMap("screen_name", screenName);
   // Test Code Debugger at work - expected closures until 2012
   String json = "";
   try {
     json = http.getPage(jtwit.TWITTER_URL + "/users/show.json", vars, http.canAuthenticate());
   } catch (Exception e) {
     // we get here?
     throw new TwitterException.E404(
         "User "
             + screenName
             + " does not seem to exist, their user account may have been removed from the service");
   }
   // Debuggers no longer at work
   if (json.length() == 0) throw new TwitterException.E404(screenName + " does not seem to exist");
   try {
     User user = new User(new JSONObject(json), null);
     return user;
   } catch (JSONException e) {
     throw new TwitterException.Parsing(json, e);
   }
 }
Beispiel #11
0
 /**
  * @param screenName
  * @param device Can be null (for do not change)
  * @param retweets Can be null (for do not change)
  * @return User object for screenName. This does not hold much info, and it can have bogus
  *     relationship (follower/following) info (bugs seen March 2013).
  */
 public User setNotifications(String screenName, Boolean device, Boolean retweets) {
   if (device == null && retweets == null) {
     return null; // no-op
   }
   Map<String, String> vars =
       InternalUtils.asMap("screen_name", screenName, "device", device, "retweets", retweets);
   String page = http.post(jtwit.TWITTER_URL + "/friendships/update.json", vars, true);
   try {
     JSONObject jo = new JSONObject(page).getJSONObject("relationship").getJSONObject("target");
     return new User(jo, null);
   } catch (JSONException e) {
     throw new TwitterException.Parsing(page, e);
   }
 }
Beispiel #12
0
 public boolean isBlocked(String screenName) {
   try {
     HashMap vars = new HashMap();
     vars.put("screen_name", screenName);
     // Returns if the authenticating user is blocking a target user.
     // Will return the blocked user's object if a block exists, and
     // error with
     // a HTTP 404 response code otherwise.
     String json = http.getPage(jtwit.TWITTER_URL + "/blocks/exists.json", vars, true);
     return true;
   } catch (TwitterException.E404 e) {
     return false;
   }
 }
Beispiel #13
0
 /**
  * @return an array of numeric user ids the authenticating user is blocking. Use {@link
  *     #showById(Collection)} if you want to convert thse into User objects.
  */
 public List<Number> getBlockedIds() {
   String json = http.getPage(jtwit.TWITTER_URL + "/blocks/ids.json", null, true);
   try {
     JSONArray arr =
         json.startsWith("[") ? new JSONArray(json) : new JSONObject(json).getJSONArray("ids");
     List<Number> ids = new ArrayList(arr.length());
     for (int i = 0, n = arr.length(); i < n; i++) {
       ids.add(arr.getLong(i));
     }
     return ids;
   } catch (JSONException e) {
     throw new TwitterException.Parsing(json, e);
   }
 }
Beispiel #14
0
 /**
  * Variant of {@link #searchUsers(String)} which gives access to later pages. Note: You can only
  * access upto the first 1000 matching results (a Twitter limitation -- c.f.
  * https://dev.twitter.com/docs/api/1.1/get/users/search).
  *
  * @param searchTerm
  * @param page Which page to retrieve (the first page is 1)
  * @return
  */
 public List<User> searchUsers(String searchTerm, int page) {
   assert searchTerm != null;
   Map<String, String> vars = InternalUtils.asMap("q", searchTerm);
   // provide paging
   if (page > 1) {
     vars.put("page", Integer.toString(page));
   }
   if (jtwit.count != null && jtwit.count < 20) {
     vars.put("per_page", String.valueOf(jtwit.count));
   }
   // yes, it requires authentication
   String json = http.getPage(jtwit.TWITTER_URL + "/users/search.json", vars, true);
   List<User> users = User.getUsers(json);
   return users;
 }
Beispiel #15
0
  /**
   * Use twitlonger.com to post a lengthy tweet. See twitlonger.com for more details on their
   * service.
   *
   * @param message Must be > 140 chars
   * @param inReplyToStatusId Can be null if this isn't a reply
   * @return A Twitter status using a truncated message with a link to twitlonger.com
   */
  public Status updateLongStatus(String message, Number inReplyToStatusId) {
    assert twitlongerApiKey != null
        : "Wrong constructor used -- you must supply an api-key to post";
    if (message.length() < 141) {
      throw new IllegalArgumentException(
          "Message too short ("
              + inReplyToStatusId
              + " chars). Just post a normal Twitter status. ");
    }
    String url = "http://www.twitlonger.com/api_post";
    Map<String, String> vars =
        InternalUtils.asMap(
            "application",
            twitlongerAppName,
            "api_key",
            twitlongerApiKey,
            "username",
            jtwit.getScreenName(),
            "message",
            message);
    if (inReplyToStatusId != null && inReplyToStatusId.doubleValue() != 0) {
      vars.put("in_reply", inReplyToStatusId.toString());
    }
    // ?? set direct_message 0/1 as appropriate if allowing long DMs
    String response = http.post(url, vars, false);
    Matcher m = contentTag.matcher(response);
    boolean ok = m.find();
    if (!ok) {
      throw new TwitterException.TwitLongerException("TwitLonger call failed", response);
    }
    String shortMsg = m.group(1).trim();

    // Post to Twitter
    Status s = jtwit.updateStatus(shortMsg, inReplyToStatusId);

    m = idTag.matcher(response);
    ok = m.find();
    if (!ok) {
      // weird - but oh well
      return s;
    }
    String id = m.group(1);

    // Once a message has been successfully posted to Twitlonger and
    // Twitter, it would be really useful to send back the Twitter ID for
    // the message. This will allow users to manage their Twitlonger posts
    // and delete not only the Twitlonger post, but also the Twitter post
    // associated with it. It will also makes replies much more effective.
    try {
      url = "http://www.twitlonger.com/api_set_id";
      vars.remove("message");
      vars.remove("in_reply");
      vars.remove("username");
      vars.put("message_id", "" + id);
      vars.put("twitter_id", "" + s.getId());
      http.post(url, vars, false);
    } catch (Exception e) {
      // oh well
    }

    // done
    return s;
  }