/*=====================================================================================*\ | The Amazon Review Tabulator - TART | | (c) 2016 by Another Floyd | | From your "Public Reviews Written by You" page on Amazon, this script collects and | | tabulates vote tallies and related information, from all of your Amazon reviews. | \*=====================================================================================*/ // ==UserScript== // @name The Amazon Review Tabulator - TART // @namespace floyd.scripts // @version 1.0.1 // @author Another Floyd at Amazon.com // @description Lists all of your reviews with vote and comment tallies, with updates highlighted // @include https://www.amazon.com/gp/cdp/member-reviews/* // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant GM_log // @downloadURL none // ==/UserScript== // Start (function() { var userId = ""; var reviewCount = 0; var reviewerRanking = ""; var helpfulVotes = 0; var urlStart = ""; var urlEnd = ""; var displayBuffer = ""; var oldStoreItemIDs = []; var oldStoreUpvotes = []; var oldStoreDownvotes = []; var oldStoreComments = []; // if I ever get this to open in a new window, instead of overwriting the Amazon // window, items below should be cleared at start of tabulate(), so that repeated runs // will work without error var newStoreItemIDs = ""; var newStoreUpvotes = ""; var newStoreDownvotes = ""; var newStoreComments = ""; var tallyUpvotes = 0; var tallyDownvotes = 0; var tallyStars = 0; var tallyComments = 0; function tabulate() { // set up top of display page displayBuffer += " \ Amazon Review Details
\ Prepared with The Amazon Review Tabulator - TART \

Top Reviewer Ranking: " + reviewerRanking + "
\ Reviews Available: " + reviewCount + "
\ Helpful Votes: " + helpfulVotes + "
\ Upvote/Review Ratio: " + (helpfulVotes/reviewCount).toFixed(2) + "

\ \ "; // read in stored info from past run, for use in change detection oldStoreItemIDs = GM_getValue("recentItemIDs", "").split(" "); oldStoreUpvotes = GM_getValue("recentUpvotes", "").split(" "); oldStoreDownvotes = GM_getValue("recentDownvotes", "").split(" "); oldStoreComments = GM_getValue("recentComments", "").split(" "); // prepare url with user ID, ready for review page number urlStart = "https://www.amazon.com/gp/cdp/member-reviews/" + userID + "?ie=UTF8&display=public&page="; urlEnd = "&sort_by=MostRecentReview"; // lots of page loading and data retrieval var perPageResponseDiv = []; var pageResponseCount = 0; var reviewsProcessed = 0; var pageCount = Math.floor(reviewCount / 10) + ((reviewCount % 10 > 0) ? 1 : 0); //var pageCount = 2; // for testing var x = 1; while (x <= pageCount) { (function(x){ var urlComplete = urlStart + x + urlEnd; perPageResponseDiv[x] = document.createElement('div'); GM_xmlhttpRequest({ method: "GET", url: urlComplete, onload: function(response) { perPageResponseDiv[x].innerHTML = response.responseText; pageResponseCount++; // see if all data from multiple page loads has arrived if(pageResponseCount==pageCount) { for(y = 1; y <= pageCount; y++) { // get parent of any reviewText DIV var findReviews = document.evaluate("//div[@class='reviewText']/..", perPageResponseDiv[y], null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); // evaluating the doc DIV made above for (var j = 0; j < findReviews.snapshotLength; j++) { var oneReview = findReviews.snapshotItem(j); var reviewChildren = oneReview.children; var childCount = reviewChildren.length; var commentCount = 0; var itemTitle = ""; var itemLink = ""; var permaLink = ""; var starRating = 0; var reviewDate = ""; var upVotes = 0; var downVotes = 0; var itemID = ""; // get number of comments, and permalink var tempText = reviewChildren[childCount-2].textContent; if(tempText.indexOf('Comment (') > -1 || tempText.indexOf('Comments (') > -1) { var paren1 = tempText.indexOf('('); var paren2 = tempText.indexOf(')'); commentCount = tempText.substring(paren1+2,paren2-1); } var lst = reviewChildren[childCount-2].getElementsByTagName('a'); permaLink = lst[2].getAttribute("href"); // get item title and item link var lst = reviewChildren[childCount-4].getElementsByTagName('a'); itemLink = lst[0].getAttribute("href"); itemTitle = lst[0].textContent; // the top few items to retrieve are done in a loop with IF checks, // because the number of entries above the review varies, depending on // whether there have been votes, if it's a verified purchase, etc. for (var i = childCount - 5; i > -1; i--) { // get star rating AND review date var childHTML = reviewChildren[i].innerHTML; var ratingClue = childHTML.indexOf('out of 5 stars'); if(ratingClue > -1) { starRating = childHTML.substring(ratingClue-4,ratingClue-1); reviewDate = reviewChildren[i].lastElementChild.textContent; } // get vote counts var childText = reviewChildren[i].textContent; var voteClue = childText.indexOf('people found the following review helpful'); if(voteClue > -1) { var list = childText.trim().split(" "); // there were extra, invisible spaces! upVotes = list[0]; var totalVotes = list[2]; downVotes = totalVotes - upVotes; } } // get item ID var lst = oneReview.parentNode.getElementsByTagName('a'); itemID = lst[0].getAttribute("name"); // get HTML formatted table row displayBuffer += prepOneTableRow((j+1+(y-1)*10),itemID,itemTitle,permaLink,reviewDate,starRating,upVotes,downVotes,commentCount); reviewsProcessed++; } } // add footer and complete results page displayBuffer += "
#ItemDateStars
UpvotesDownvotes% Helpful
Comments
" + (tallyStars/reviewsProcessed).toFixed(1) + "" + tallyUpvotes + "" + tallyDownvotes + "" + helpfulPercent(tallyUpvotes,tallyDownvotes) + "" + tallyComments + "
"; // store info to be used in subsequent run, for change detection GM_setValue("recentItemIDs", newStoreItemIDs.trim()); GM_setValue("recentUpvotes", newStoreUpvotes.trim()); GM_setValue("recentDownvotes", newStoreDownvotes.trim()); GM_setValue("recentComments", newStoreComments.trim()); // display results page document.body.innerHTML = displayBuffer; } } }); })(x); x++; } } function helpfulPercent(upVotes,downVotes) { var helpfulPercent = ""; upVotes = parseInt(upVotes); downVotes = parseInt(downVotes); if(upVotes + downVotes > 0) helpfulPercent = (upVotes/(upVotes+downVotes)*100).toFixed(1); return helpfulPercent; } function prepOneTableRow (row,itemID,itemTitle,permaLink,reviewDate,starRating,upVotes,downVotes,commentCount) { // do these before mangling the values with tags var helpfulPct = helpfulPercent(upVotes,downVotes); itemTitle = "" + itemTitle.substring(0,65) + ""; // keep tallies to use in table footer tallyUpvotes += parseInt(upVotes); tallyDownvotes += parseInt(downVotes); tallyStars += parseInt(starRating); tallyComments += parseInt(commentCount); // assemble storage info, to use in subsequent run, for change detection newStoreItemIDs += itemID + " "; newStoreUpvotes += upVotes + " "; newStoreDownvotes += downVotes + " "; newStoreComments += commentCount + " "; // see if review for this item has previously been examined var matchIdx = -1; for(var i=0; i -1) { // entry exists; see if any of the numbers have changed if(oldStoreUpvotes[matchIdx] != upVotes) { // for changed number, make it bold, and hilite row upVotes = "" + upVotes + ""; hiliteRow = true; } if(oldStoreDownvotes[matchIdx] != downVotes) { downVotes = "" + downVotes + ""; hiliteRow = true; } if(oldStoreComments[matchIdx] != commentCount) { commentCount = "" + commentCount + ""; hiliteRow = true; } } else { // no match, so, it's a new review; bold the title and hilite the row itemTitle = "" + itemTitle + ""; hiliteRow = true; } var tdLeft = ((hiliteRow===true)? "" : ""); var tdRight = ((hiliteRow===true)? "" : ""); var tableRow = "" + tdLeft + row + "" + tdLeft + itemTitle + "" + tdLeft + reviewDate + "" + tdRight + starRating + "" + tdRight + upVotes + "" + tdRight + downVotes + "" + tdRight + helpfulPct + "" + tdRight + commentCount + ""; return tableRow; } //--- global event listeners allow working across scopes document.addEventListener('click', function(event) { var tempstr = new String(event.target); if(tempstr.indexOf('tabulate') > -1) { tabulate(); event.stopPropagation(); event.preventDefault(); } }, true); //--- main script block from this point function Tabulate_Amazon_Reviews_Run() { // find profile info panel var findDiv = document.evaluate("//div[contains(.,'Helpful Votes')]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); var profileDiv = findDiv.snapshotItem(0); // get reviewer ranking and user ID var lst = profileDiv.getElementsByTagName('a'); reviewerRanking = lst[0].textContent; var charIdx = lst[0].getAttribute("href").indexOf('#'); userID = lst[0].getAttribute("href").substring(charIdx+1); // get helpful votes charIdx = profileDiv.textContent.lastIndexOf(':'); helpfulVotes = profileDiv.textContent.substring(charIdx+2); // get review count var prevSibDiv = profileDiv.previousElementSibling; charIdx = prevSibDiv.textContent.lastIndexOf(':'); reviewCount = prevSibDiv.textContent.substring(charIdx+2); // add Tabulate link profileDiv.innerHTML += "

Tabulate"; } Tabulate_Amazon_Reviews_Run(); })(); // End