Не жалко конечно, тем более что первые два из открытых источников:
1) https://gist.github.com/deymosD - это ShowImageInfo и ShowDownloadLocations.
2) Это для показа дневной статистики продажи вектора и растра, отметка растра, плюс переменной newfrom можно задать индекс картинки для разделения на новый и старый контент. Писалось для себя и под свои нужды, плюс первая попытка написания скриптов со слабым знанием яваскрипт, по стилю конечно "гавнокод", но работает. Проверено только на связке chrome+tampermonkey.
Как выглядит результат работы скрипта? Можно скриншот?
Да, можно, только портфель не мой и заскриншотить разрешили только при условии полной анонимности. Не думал, что стокеры настолько суеверные....
Итак, на первом скриншоте в середине результат работы моего скрипта (по дневной статистике без разделения на новый или старый контент), календарь слева и инфо справа это работа ShowImageInfo по ссылке с github. Скриншот 2 - панель слева это второй скрипт с github под названием ShowDownloadLocations. Ну и на последнем мой скрипт по удалению батчей который сейчас тестирую. Хотя по последнему скриншоту трудно понять его работу...
народ, вы не боитесь ставить неизвестно что себе на шаттер?
Честно говоря подобный страх оправдан ибо доверяясь автору скрипта нужно быть уверенным ещё в том, что он сам относится к безопасности серьёзно. Возможности скриптов большие. Приведу пример, скрипт shutter places которым и я пользовался до того как нашёл аналог - конечно хороший и автор заслуживает на мой взгляд доверия, но то, что установлено на компьютере это только загрузчик основного скрипта который постоянно живёт на github автора. Разумеется это сделано для удобства, автор в любой момент внесёт изменения и они автоматически начнут работать у всех пользователей. Но что если кто-либо получит доступ к его аккаунту на github? Он встроит в скрипт вредоносный функционал и может запросто получить доступ а аккаунтам пользователей скрипта...
Я немного знаком с программированием по этому прежде чем установить что либо обязательно изучаю код, ну а остальным советую конечно же быть осторожными. В конце концов найдя что-то можно выложить и спросить совета не опасно ли использовать. Уверен, что тут есть много людей которые хорошо разбираются в javascript.
// NEW:
// v1.8 - added DatePicker, support for async call to get daily or montly stats, made all divs draggable
// v1.7 - moving popup div enabled
'use strict';
var $j = jQuery.noConflict();
// =========== PARAMETERS ===========
var enableDatePicker = true; // if you don't need date picker, set this to false
var loadMonthyEarningsOnYMChange = true; // set to false to disable loading earnings page when month or year are changed in date picker
// ==/UserScript==
// in reverse image search, don't return results from stock sites (idea by mandritoiu); add other sites in the form --> +-site:.domain.com (sometimes Google ignores this):
var noStockSites = "-site:dreamstime.com+-site:shutterstock.com+-site:shutterstock.in+-site:istockphoto.com+-site:fotolia.com+-site:123rf.com+-site:veer.com+-site:istockphoto.com";
// not sure why they q= and oq= are used, but here are both :D, can't hurt; i could do it much nicer, maybe in the future... :)
// Google Images sometimes ignores excludes and will serve content from SS or other excluded sites
// i use smoothness theme for the datepicker and here we load external CSS
if (enableDatePicker) {
var link = window.document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/smoothness/jquery-ui.css'; // get smoothness CSS; check http://jqueryui.com/themeroller/ for others, just change the theme name in url
document.getElementsByTagName("HEAD")[0].appendChild(link); // other themes: http://rtsinani.github.io/jquery-datepicker-skins/, have fun!
}
$j(document).ready(function() {
CreateStyles();
div = document.createElement('div');
div.className = "gginfo";
if (localStorage.getItem("positionImageInfo")) {
var position = $j.parseJSON(localStorage.getItem("positionImageInfo"));
div.style.top = position.top + "px";
div.style.left = position.left + "px";
}
function addDatePicker() {
// wrap table element with div.ggHack because we're gonna need to import HTML content of different pages
$j("div.shutterstock_submit_page table:first").wrap("<div class='ggHack'></div>");
// get date from URL
var datepicker = document.createElement('div');
datepicker.id = "datepicker";
if (localStorage.getItem("positionDatePicker")) {
var position = $j.parseJSON(localStorage.getItem("positionDatePicker"));
datepicker.style.top = position.top + "px";
datepicker.style.left = position.left + "px";
}
$j("div#datepicker").datepicker({ // check https://api.jqueryui.com/datepicker/ for API and play with options
maxDate: "+0D", // not much fun to go beyond today, no stats will be available
showOtherMonths: true,
changeMonth: true,
changeYear: true,
defaultDate: window.location.href.match(/date=(\d\d\d\d\-\d\d\-\d\d)/)[1], // get the default date from the URL
dateFormat:"yy-mm-dd",
firstDay: 1, // start with monday, set to 0 for sunday (but why!?)
showButtonPanel: true,
currentText: "This month",
yearRange:"2003:+0", // don't want to go to pre-Shutterstock times...
onSelect: function(selected,event) {
updateTable(selected);
$j("div.gginfo").show(); // when we select date, load stats for the date and show the image info div
}
});
// add this only if selected in params above
if (loadMonthyEarningsOnYMChange) {
$j("div#datepicker").datepicker("option", "onChangeMonthYear", function (year, month, i) { // when we change month or year, load earnings for that month in that year
if (month < 10) month = "0" + month;
var yearMonth = year + "-" + month;
var monthLink = "http://submit.shutterstock.com/stats.mhtml?year_month=" + yearMonth;
$j("<link/>", {
rel: "stylesheet",
type: "text/css",
href: "/css/stats.css?rev=1" // we need to add style for statistics table
}).appendTo("head");
$j("div.shutterstock_submit_page table:first").html("<h2>Loading...</h2>");
$j("div.shutterstock_submit_page center div").text(yearMonth);
$j("div.shutterstock_submit_page div.ggHack").load(monthLink + " div.shutterstock_submit_page table#stats-table");
$j("div.gginfo").hide();
});
}
}
function updateTable(date){
var newLink = "http://submit.shutterstock.com/stats_date.mhtml?date=" + date;
$j("div.shutterstock_submit_page table:first").html("<h2>Loading...</h2>");
$j("div.shutterstock_submit_page center div").text(date);
$j("div.shutterstock_submit_page div.ggHack").load(newLink + " div.shutterstock_submit_page table:first", function() {
fixLinksinDailyStats(); // gotta do that cause we just reloaded content
});
}
function resetDivInfo(){
$j("div.gginfo").html("<b>Click on image ID to show image info.</b>");
return;
}
function fixLinksinDailyStats(){
$j("a.link").each(function() {
var ahref = this.href.match(/.*www.*id=(\d*)$/);
if (ahref) {
var href = ahref[1];
$(this).removeAttribute("href");
$(this).on("click","a.link", function() {
if (opened != href) {
GetImageData(href);
$j("div.gginfo").show();
}
opened = href; // remember which image is still opened
} );
}
});
}
function GetImageData(imageID) {
div.innerHTML = "<h4>Loading...</h4>";
var d = new Date();
var n = d.getTimezoneOffset() / 60;
$j.ajax({
url: window.location.protocol + '//submit.shutterstock.com/show_component.mhtml?component_path=mobile/comps/image_detail.mj&photo_id=' + imageID,
type: "get",
dataType: "html",
cache: true,
error: function (request, status, error) {
console.log(request.responseText);
},
success: function( data ){
var imageInfo = $j.parseJSON(data);
if (imageInfo) {
var downloads = imageInfo.latest_downloads;
var keywords = imageInfo.keywords;
var totals = imageInfo.totals;
var today = totals.today;
var all = totals.all_time;
var table;
div.innerHTML = "<span class=\"closeInfo\">Close</span><br />";
div.innerHTML += "<h4>Image statistics</h4>";
div.innerHTML += "<a target=\"_new\" href=\"http://www.shutterstock.com/pic.mhtml?id=" + imageID + "\"><img align=\"right\" class=\"resize\" src=\"http:" + imageInfo.thumb_url + "\" /></a>";
div.innerHTML += "<h5> " + imageInfo.description + "</h5>";
div.innerHTML += "<b>Image ID:</b> <a target=\"_new\" href=\"http://www.shutterstock.com/pic.mhtml?id=" + imageID + "\">" + imageID + "</a><br />";
if (downloads.length > 0) {
div.innerHTML += "<br /><b>Latest downloads</b> (max 20 or max last 365 days):</b><br />";
table = "<table width=\"300px\">";
table += "<thead><th align=\"left\">Date</th><th align=\"right\">Earnings</th></thead><tbody>";
downloads.forEach(function(arg) {
var date = new Date ( ((arg.date_time/1000) + (6+n) * 3600)*1000).toUTCString().toLocaleString();
table += "<tr><td align=\"left\">" + date + "</td><td align=\"right\">" + arg.amount + "</td></tr>";
});
table += "</tbody></table><br /";
div.innerHTML += table;
}
else
{
div.innerHTML += "<br /><b>No downloads in the last 365 days.</b><br />";
}
}
$j("span.closeInfo").on("click", function(){
// $j("div.gginfo").hide(); // i'd rather keep the info on the screen than hide the div
resetDivInfo();
opened = 0;
});
}
});
}
// following code created by https://gist.github.com/satinka/5479a93d389a07d41246
function CreateStyles() {
var sheet = (function() {
var style = document.createElement("style");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
return style.sheet;
})();
// NEWS
// v1.6: hashes SS response for location and image earnings
// enables dragging page elements and moving them around; stores positions across requests (to disable, remove div#* keys from localStorage or set makeOriginalDivsDraggable to false, line #30
// if trackMySales enabled, stores info about downloaded images in local storage; objective: create arrival rate distribution
'use strict';
var useShortCountryName = false; // US (true), or United States of America (false) - false is now default as it looks nicer :)
var googleMaps = "https://www.google.com/maps/place/";
var displayEarnings = true; // set to false to disable display of earnings for last 7 days and today on top of popup
var displayRecentEarnings = true; // set to false to disable display of earnings for recent images
var makeOriginalDivsDraggable = true; // makes content on front page draggable, you can move sections around (map, track your sets, graphs, content overview, profile, forum and blog
var debug = false; // easier for me during development
var trackMySales = true; // for future development, saves info on individual sales in local storage
div = document.createElement('div');
div.id = "ggDL";
$j("div#dragContainer").append(div);
if (localStorage.getItem("positionDownloadLocations")) {
var position = $j.parseJSON(localStorage.getItem("positionDownloadLocations"));
$j("div#dragContainer").css({
top: position.top,
left: position.left});
}
$j.each(coords, function( ind, el ) {
var id = el.media_id;
var img = el.thumb_url;
var time = el.time;
var loc;
if (el.latitude !== null && el.longitude !== null) {
$j.ajax({
url: 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + el.latitude + ',' + el.longitude,
type: "get",
dataType: "html",
error: function (request, status, error) {
console.log(request.responseText);
},
success: function( data ){
var res = $j.parseJSON(data);
// moramo ovako jer je asinkrono. dok u divu ispise tekst, ovo jos nije stiglo sa servera
if (res.status == "OK") {
$j("a.location" + id + "-" + time).text(ExtractLocation(res.results[0].address_components));
}
else {
$j("a.location" + id + "-" + time).text("Can't convert to location :\(");
}
}
});
}
if (trackMySales) {
localStorage.setItem(id + "-" + time, JSON.stringify(el)); // save image info, key = (id-time_of_download);
}
if (debug) { console.log("Added " + id + "to local storage"); }
// if it's footage, need to change thumbnail size; too bad i can't test it with 1 footage a century
var footageWidth = "";
if (el.media_type != "photo") {
footageWidth = "width=\"100px\" height=\"59\" ";
}
div.innerHTML += "<a target=\"_new\" href=\"http://www.shutterstock.com/pic.mhtml?id=" + id + "\"><img " + footageWidth + "src=\"" + img + "\" /></a><br />";
var n = new Date().getTimezoneOffset() / 60; // offset from GMT
// taking only time from date - 6+n - NY time + offset from GMT gives local - works wine for me
var t = new Date((time + (6+n) * 3600) *1000).toTimeString().split(" ")[0];
if (displayRecentEarnings) {
div.innerHTML += "Earnings: <span id=\"earnings" + id + time + "000\">N/A</span><br />";
if (debug) {console.log(time)};
}
div.innerHTML += "Time: " + t + "<hr />";
});
function retrieveLastWeekEarnings(){
$j.ajax({
url: 'http://submit.shutterstock.com/show_component.mhtml?component_path=mobile/comps/earnings_overview.mj',
type: "get",
dataType: "html",
error: function (request, status, error) {
console.log(request.responseText);
},
success: function( data ){
if (existsInLocalStorage('lastSevenDays', data)) {
retrieveEarnings();
$j("div.refreshCoords").text("Refresh");
return true;
}
var res = $j.parseJSON(data);
// moramo ovako jer je asinkrono. dok u divu ispise tekst, ovo jos nije stiglo sa servera
if (res.last_7_days) {
$j("span#last7").text(res.last_7_days);
}
if (res.day) {
$j("span#today").text(res.day);
}
// if (res.unpaid) {
// $j("span#unpaid").text(res.unpaid);
// }
// if (res.lifetime) {
// $j("span#lifetime").text(res.lifetime);
// }
}
});
}
// retreive earnings for last 7 days for each image: http://submit.shutterstock.com/show_component.mhtml?component_path=mobile/comps/earnings_list.mj
// and put that info in the appropriate DIV
function retrieveEarnings(){
if (displayRecentEarnings) {
$j.ajax({
url: 'http://submit.shutterstock.com/show_component.mhtml?component_path=mobile/comps/earnings_list.mj',
type: "get",
dataType: "html",
error: function (request, status, error) {
console.log(request.responseText);
},
success: function( data ){
if (existsInLocalStorage('lastEarnings', data)) {
$j("span.refreshCoords").text("Refresh");
return true;
}
var res = $j.parseJSON(data);
var day=0; // retrieve for today, will increase if <10 dls today
var retrievedImages = 0; // count number of retrieved, stop at 10
while (retrievedImages < 10) {
var downloads = res[day].downloads;
$j.each(downloads, function (ind, el) {
var imageID = el.photo_id;
var earnings = el.payout;
var date = el.download_date;
if (debug) {console.log("ID: " + imageID + ", Earnings: " + earnings + ", Date: " + date)};
$j("span#earnings" + imageID + date ).text(earnings + "$");
retrievedImages++;
if (retrievedImages >= 10) return false;
});
day++;
if (debug) console.log(day, retrievedImages);
}
}
});
}
}
// following code created by https://gist.github.com/satinka/5479a93d389a07d41246
function ExtractLocation(details) { // created by https://gist.github.com/satinka/5479a93d389a07d41246
var loc = "";
var country = "";
var locality = "";
var admin_area1 = "";
var admin_area2 = "";
$j.each(details, function( ind, el ) {
if ($j.inArray("country", el.types) != -1)
country = useShortCountryName ? el.short_name : el.long_name;
if ($j.inArray("locality", el.types) != -1)
locality = el.long_name;
if ($j.inArray("administrative_area_level_1", el.types) != -1)
admin_area1 = el.short_name;
if ($j.inArray("administrative_area_level_2", el.types) != -1)
admin_area2 = el.long_name;
});
loc = loc + ((locality !== "") ? locality + ", " : "") +
((admin_area2 != "") ? admin_area2 + ", " : "") +
((admin_area1 != "") ? admin_area1 + ", " : "") +
((country !== "") ? country : "");
return loc;
}
function createStyles() {
var sheet = (function() {
var style = document.createElement("style");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
return style.sheet;
})();
var refreshCoords = "cursor: hand; cursor: pointer; text-decoration: underline;";