Greasy Fork

Greasy Fork is available in English.

The Amazon Review Tabulator - TART

Lists all of your reviews with vote and comment tallies

当前为 2016-10-30 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

/*=====================================================================================*\
|  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
// @include        https://www.amazon.com/gp/cdp/member-reviews/*
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_xmlhttpRequest
// @grant          GM_log
// ==/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 += "<style type='text/css'> \
    .tg  {border-collapse:collapse;border-spacing:0} \
    .tg td{font-family:Arial, sans-serif;font-size:12px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal} \
    .tg th{font-family:Arial, sans-serif;font-size:12px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal} \
    .tg .header-left{font-weight:bold;background-color:#010066;color:#ffffff;text-align:left} \
    .tg .header-right{font-weight:bold;background-color:#010066;color:#ffffff;text-align:right} \
    .tg .cell-left{text-align:left} \
    .tg .cell-right{text-align:right} \
    .tg .hilite-left{text-align:left;background-color:#FFFF12} \
    .tg .hilite-right{text-align:right;background-color:#FFFF12} \
    </style> \
	<span style='font-size:16px;font-weight:bold'>Amazon Review Details</span><br> \
	<span style='font-size:8px'>Prepared with The Amazon Review Tabulator - TART</span> \
	<p>Top Reviewer Ranking: " + reviewerRanking + "<br> \
	Reviews Available: " + reviewCount + "<br> \
	Helpful Votes: " + helpfulVotes + "<br> \
	Upvote/Review Ratio: " + (helpfulVotes/reviewCount).toFixed(2) + "<br></p> \
	<table class='tg'> \
    <tr><th class='header-left'>#</th><th class='header-left'>Item</th><th class='header-left'>Date</th><th class='header-right'>Stars<br></th><th class='header-right'>Upvotes</th><th class='header-right'>Downvotes</th><th class='header-right'>% Helpful<br></th><th class='header-right'>Comments</th></tr>";
	
	// 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 += "<tr><td class='header-left'></td><td class='header-left'></td><td class='header-left'></td><td class='header-right'>" + (tallyStars/reviewsProcessed).toFixed(1) + "</td><td class='header-right'>" + tallyUpvotes + "</td><td class='header-right'>" + tallyDownvotes + "</td><td class='header-right'>" + helpfulPercent(tallyUpvotes,tallyDownvotes) + "</td><td class='header-right'>" + tallyComments + "</td></tr></table>";
						
						// 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 <b> tags </b>
	var helpfulPct = helpfulPercent(upVotes,downVotes); 
	itemTitle = "<a href='" + permaLink + "' target='_new'>" + itemTitle.substring(0,65) + "</a>";
	
	// 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<oldStoreItemIDs.length; i++) {
		if(oldStoreItemIDs[i] == itemID) {
			// we have a match, an item that has previously been seen
			matchIdx = i;
			break;
		}
	}
			
	var hiliteRow = false;	
	if(matchIdx > -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 = "<b>" + upVotes + "</b>";
			hiliteRow = true;
		}
		if(oldStoreDownvotes[matchIdx] != downVotes) {
			downVotes = "<b>" + downVotes + "</b>";
			hiliteRow = true;
		}
		if(oldStoreComments[matchIdx] != commentCount) {
			commentCount = "<b>" + commentCount + "</b>";
			hiliteRow = true;
		}
	}
	else {
		// no match, so, it's a new review; bold the title and hilite the row
		itemTitle = "<b>" + itemTitle + "</b>";
		hiliteRow = true;		
	}

	var tdLeft = ((hiliteRow===true)? "<td class='hilite-left'>" : "<td class='cell-left'>");
	var tdRight = ((hiliteRow===true)? "<td class='hilite-right'>" : "<td class='cell-right'>");
	
	var tableRow = "<tr>" + tdLeft + row + "</td>" + tdLeft + itemTitle + "</td>" + tdLeft + reviewDate + "</td>" + tdRight + starRating + "</td>" + tdRight + upVotes + "</td>" + tdRight + downVotes + "</td>" + tdRight + helpfulPct + "</td>" + tdRight + commentCount + "</td></tr>";

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 += "<br></br><a href='javascript:tabulate();'>Tabulate</a>";
	
}
   
Tabulate_Amazon_Reviews_Run();

})();
// End