@Override public void handleItemList(IItemListHandler handler, long syncTime) throws IOException, ReaderException { // http://www.google.com/reader/api/0/stream/contents/user%2F-%2Fstate%2Fcom.google%2Fread?client=newsplus&output=json&ck=1276066665822&n=20&r=n Reader in = null; try { long startTime = handler.startTime(); in = readStreamContents(syncTime, startTime, handler, null); String continuation = parseItemList(in, handler); int limit = handler.limit(); int max = limit > SYNC_MAX_ITEMS ? SYNC_MAX_ITEMS : limit; int count = 1; // continuation count while ((limit == 0 || limit > max * count) && handler.continuation() && continuation != null && continuation.length() > 0) { in.close(); in = readStreamContents(syncTime, startTime, handler, continuation); continuation = parseItemList(in, handler); count++; } } catch (JsonParseException e) { e.printStackTrace(); throw new ReaderException("data parse error", e); } catch (RemoteException e) { e.printStackTrace(); throw new ReaderException("remote connection error", e); } finally { if (in != null) in.close(); // ensure resources get cleaned up timely } }
// NOTE: /api/0/stream/contents private Reader readStreamContents( long syncTime, long startTime, IItemListHandler handler, String continuation) throws IOException, ReaderException, RemoteException { initAuth(); StringBuilder buff = new StringBuilder(URL_API_STREAM_CONTENTS.length() + 128); buff.append(URL_API_STREAM_CONTENTS); String stream = handler.stream(); if (stream != null) { if (stream.equals(STATE_READING_LIST)) stream = STATE_GOOGLE_READING_LIST; else if (stream.equals(STATE_STARRED)) stream = STATE_GOOGLE_STARRED; buff.append("/").append(Utils.encode(stream)); } buff.append("?client=newsplus&ck=").append(syncTime); if (handler.excludeRead()) { buff.append("&xt=").append(STATE_GOOGLE_READ); } if (continuation != null && continuation.length() > 0) { buff.append("&c=").append(continuation); } if (startTime > 0) { buff.append("&ot=").append(startTime); } int limit = handler.limit(); limit = (limit > SYNC_MAX_ITEMS || limit == 0) ? SYNC_MAX_ITEMS : limit; if (limit > 0) { // google only allows max 1000 at once buff.append("&n=").append(limit > SYNC_MAX_ITEMS ? SYNC_MAX_ITEMS : limit); } buff.append("&r=").append(handler.newestFirst() ? "n" : "o"); return doGetReader(buff.toString()); }
private String parseItemList(Reader in, IItemListHandler handler) throws JsonParseException, IOException, RemoteException { JsonFactory f = new JsonFactory(); JsonParser jp = f.createParser(in); long length = 0; String currName; String mediaUrl = null; String mediaType = null; IItem entry = null; String continuation = null; List<IItem> itemList = new ArrayList<IItem>(); List<String> excludedSubs = handler.excludedStreams(); // excluded subscriptions jp.nextToken(); // will return JsonToken.START_OBJECT (verify?) while (jp.nextToken() != JsonToken.END_OBJECT) { currName = jp.getCurrentName(); jp.nextToken(); // move to value, or START_OBJECT/START_ARRAY if ("continuation".equals(currName)) { continuation = jp.getText(); } else if ("items".equals(currName)) { // contains an object // start items while (jp.nextToken() != JsonToken.END_ARRAY) { // request stop // if (handler.requestStop()) throw new JsonParseException(null, null); if (jp.getCurrentToken() == JsonToken.START_OBJECT) { entry = new IItem(); } else if (jp.getCurrentToken() == JsonToken.END_OBJECT) { if (entry != null && entry.uid.length() > 0) { if (length + entry.getLength() > MAX_TRANSACTION_LENGTH) { handler.items(itemList, STRATEGY_INSERT_DEFAULT); itemList.clear(); length = 0; } itemList.add(entry); length += entry.getLength(); } if (itemList.size() % 200 == 0 || length > MAX_TRANSACTION_LENGTH) { // avoid TransactionTooLargeException, android only // allows 1mb handler.items(itemList, STRATEGY_INSERT_DEFAULT); itemList.clear(); length = 0; } entry = null; } currName = jp.getCurrentName(); if (currName == null || entry == null) continue; jp.nextToken(); // move to value if (currName.equals("id")) { entry.uid = stripItemUid(jp.getText()); } else if (currName.equals("crawlTimeMsec")) { entry.updatedTime = Long.valueOf(jp.getText()) / 1000; } else if (currName.equals("title")) { entry.title = Utils.stripTags(unEscapeEntities(jp.getText()), true); } else if (currName.equals("categories")) { while (jp.nextToken() != JsonToken.END_ARRAY) { String category = jp.getText(); if (category != null && addUserLabel(category, entry)) { entry.addTag(category); } if (category != null && category.endsWith("/state/com.google/read")) { entry.read = true; } } } else if (currName.equals("published")) { entry.publishedTime = jp.getLongValue(); } else if (currName.equals("alternate")) { while (jp.nextToken() != JsonToken.END_ARRAY) { currName = jp.getCurrentName(); if (currName == null) continue; jp.nextToken(); if (currName.equals("href")) { entry.link = jp.getText(); } else { jp.skipChildren(); } } } else if (currName.equals("enclosure")) { while (jp.nextToken() != JsonToken.END_ARRAY) { currName = jp.getCurrentName(); if (currName == null) continue; jp.nextToken(); if (currName.equals("href")) { mediaUrl = jp.getText(); } else if (currName.equals("type")) { mediaType = jp.getText(); if (mediaType.startsWith("image")) { entry.addImage(mediaUrl, mediaType); } else if (mediaType.startsWith("video")) { entry.addVideo(mediaUrl, mediaType); } else if (mediaType.startsWith("audio")) { entry.addAudio(mediaUrl, mediaType); } mediaUrl = null; mediaType = null; } else { jp.skipChildren(); } } } else if (currName.equals("summary") || currName.equals("content")) { while (jp.nextToken() != JsonToken.END_OBJECT) { currName = jp.getCurrentName(); if (currName == null) continue; jp.nextToken(); if (currName.equals("content")) { entry.content = unEscapeEntities(jp.getText()); } else { jp.skipChildren(); } } } else if (currName.equals("author")) { entry.author = jp.getText(); } else if (currName.equals("origin")) { while (jp.nextToken() != JsonToken.END_OBJECT) { currName = jp.getCurrentName(); if (currName == null) continue; jp.nextToken(); if (currName.equals("streamId")) { String streamId = jp.getText(); if (streamId != null && (excludedSubs == null || !excludedSubs.contains(streamId))) { entry.subUid = streamId; } else entry = null; } else { jp.skipChildren(); } } } else { jp.skipChildren(); } } handler.items(itemList, STRATEGY_INSERT_DEFAULT); itemList.clear(); } else { jp.skipChildren(); } } return continuation; }