Skip to content

Instantly share code, notes, and snippets.

@vatho
Last active September 25, 2017 21:50
Show Gist options
  • Save vatho/90f9885d8f95ca446541f87f2f2365ce to your computer and use it in GitHub Desktop.
Save vatho/90f9885d8f95ca446541f87f2f2365ce to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Enhance Dota builds page
// @namespace https://gist.github.com/parnakra/90f9885d8f95ca446541f87f2f2365ce
// @version 0.6
// @updateURL https://gist.github.com/parnakra/90f9885d8f95ca446541f87f2f2365ce/raw/
// @description Adds sorting, searching, filtering and publishing functionality to Dota builds list
// @author Parnakra
// @match http://www.dota2.com/workshop/builds
// @grant none
// ==/UserScript==
(function() {
var intervalId = window.setInterval(function() { if(g_bHeroDataReady) { enhance(); window.clearInterval(intervalId); }}, 1000);
function enhance() {
var startDateId = 'startDate',
endDateId = 'endDate',
buildsTableId = 'buildsTable';
addPublishButton();
$.getScript("//cdn.datatables.net/1.10.11/js/jquery.dataTables.min.js", function() {
addCss();
initializeTable();
addDateFilters();
loadExtension();
//hideOriginal();
});
function addPublishButton() {
$('#fileOperationsContent > h3')[0].insertAdjacentHTML('afterend', '<input type="button" class="largeButton" onclick="publishBuilds()" value="Publish all builds" />');
}
window.publishBuilds = function() {
let buildsToPublish = [];
jQuery.ajaxSetup({async:false});
for(let i=0;i<g_Builds.buildInfo.length;i++) {
let build = g_Builds.buildInfo[i];
if(build.published && build.localEdits) {
let buildUrl = 'http://www.dota2.com/workshop/builds/update?fileid=' + build.ugcid + '&publishedfileid=' + build.publishedFileId;
buildsToPublish.push({
'buildUrl': buildUrl,
'agree': 'on',
'cloudFileName': build.filename,
'heroName': build.heroName,
'heroTag': g_rgHeroData[build.heroName].dname.replace("'", ""),
'title': build.title,
'publishedfileid': build.publishedFileId
});
}
}
var maxBuildsToPublish = 10;
if(buildsToPublish.length > 0) {
var confirmationMessage = 'Will now publish the following ' + Math.min(maxBuildsToPublish, buildsToPublish.length) + ' out of ' + buildsToPublish.length + ' builds:\n\n';
for(let i=0;i<Math.min(maxBuildsToPublish, buildsToPublish.length);i++) {
let build = buildsToPublish[i];
$.get(build.buildUrl, function(data) {
var desc = $(data).find('[name="desc"]').val();
var privacy = $(data).find('[name="privacy"]').val();
var language = $(data).find('[name="language"]').val();
build.desc = desc;
build.language = language;
build.privacy = privacy;
});
confirmationMessage += build.title + ' - ' + build.desc + '\n';
}
if(window.confirm(confirmationMessage)) {
console.log('updating builds');
let skippedBuilds = '';
for(let i=0;i<buildsToPublish.length;i++) {
let request = new XMLHttpRequest();
let formData = new FormData();
let build = buildsToPublish[i];
if(!build.desc || !build.language || !build.privacy) {
skippedBuilds += 'skipped ' + build.title + '\n';
continue;
}
formData.append("desc", build.desc);
formData.append("language", build.language);
formData.append("privacy", build.privacy);
formData.append("agree", build.agree);
formData.append("cloudFileName", build.cloudFileName);
formData.append("heroName", build.heroName);
formData.append("heroTag", build.heroTag);
formData.append("title", build.title);
formData.append("publishedfileid", build.publishedfileid);
request.open("POST", "http://www.dota2.com/workshop/builds/submit_update");
request.send(formData);
console.log('updated build ' + build.title);
};
if(skippedBuilds) {
alert('Not all builds were published succesfully. Try again or publish them manually.\n' + skippedBuilds)
} else {
alert('All builds published!');
}
window.location.reload();
};
} else {
alert('No builds to publish');
}
jQuery.ajaxSetup({async:true});
}
function hideOriginal() {
let heading = $("#fileOperationsContent > h3");
heading.click(function() { $('#files').toggle();});
heading.css('cursor', 'pointer')
$('#files').hide();
}
function loadExtension() {
$.fn.dataTableExt.afnFiltering.push(
function( oSettings, aData, iDataIndex ) {
var startDate = document.getElementById(startDateId).value,
endDate = document.getElementById(endDateId).value,
dateCol = 5,
buildDate=new Date(aData[dateCol]);
if ( startDate === "" && endDate === "" )
{
return true;
}
else if ( startDate !== "" && endDate === "")
{
return new Date(startDate) <= buildDate;
}
else if (endDate !== "" && startDate === "")
{
return new Date(endDate) >= buildDate;
}
else if (new Date(startDate) <= buildDate && new Date(endDate) >= buildDate)
{
return true;
}
return false;
}
);
}
function addCss() {
var dataTablesCssId = 'datatablesCss';
if($('#' +dataTablesCssId).length === 0) {
console.log('datatables css not found, adding now');
$('head').append('<link id="' + dataTablesCssId + '" rel="stylesheet" href="//cdn.datatables.net/1.10.11/css/jquery.dataTables.min.css" type="text/css" />');
}
}
function redrawTable() {
$('#' + buildsTableId).DataTable().draw();
}
function addDateFilters() {
var startDateInput = $('<input id="' + startDateId + '" type="datetime-local"></input>');
var endDateInput = $('<input id="' + endDateId + '" type="datetime-local"></input>');
startDateInput.change(redrawTable);
endDateInput.change(redrawTable);
$('#fileOperationsContent').append(startDateInput);
$('#fileOperationsContent').append(endDateInput);
}
function initializeTable() {
jQuery.ajaxSetup({async:false});
customQueryForCloudFileDetails(0); // get build info for all builds (not only the ones on current page)
jQuery.ajaxSetup({async:true});
var buildsTable = $('#'+buildsTableId);
if(buildsTable.length === 0) {
console.log('No table found, creating new one');
buildsTable = $('<table id="' + buildsTableId + '" />');
$('#fileOperationsContent').append(buildsTable);
} else {
return;
}
var builds = [];
for(var i=0;i<g_Builds.buildInfo.length;i++){
let build = g_Builds.buildInfo[i];
let heroData = g_rgHeroData[build.heroName];
if(!heroData) {
console.log('No data found for', build, g_rgHeroData);
}
builds.push([
i,
build.heroPortrait,
build.heroName + ' ' + heroData.dname,
build.title,
build.filename,
new Date(build.timestamp*1000)]);
}
buildsTable.DataTable({
data: builds,
columns: [
{ title: "index", render: function(data, type, row) { return '<div class="fileOperationSelector disableClickClear" index="' + data + '" onclick="selectorClicked(this)"></div>'; }},
{ title: ""},
{ title: "Hero", visible: false},
{ title: "Title",
width: '80%',
render: function(data, type, row) { return '<div style="cursor: pointer" onclick="fileSectionClicked(' + row[0] + ')">' + data + '</div>'} },
{ title: "filename", visible: false },
{ title: "Time" }
],
paging: false,
});
}}
function customQueryForCloudFileDetails(startIndex) {
// Post for our details
var numResults = Math.min( NUM_BUILDS_PER_PAGE, g_TotalFiles );
var targetFileIds = [];
for ( var i = startIndex; i < g_Builds.buildInfo.length; i++ ) {
// Don't cache something we already have
if ( g_Builds.buildInfo[i].hasOwnProperty('cached') && g_Builds.buildInfo[i].cached )
continue;
// Add to the request
targetFileIds.push({
ugcid: g_Builds.buildInfo[i].ugcid,
filename: g_Builds.buildInfo[i].filename,
timestamp: g_Builds.buildInfo[i].timestamp
});
}
// Handle the "all cached" case
if ( targetFileIds.length == 0 ) {
populateCloudFiles();
return;
}
showLoadingEffects();
// Do the actual POST
$.post( 'http://www.dota2.com/workshop/builds/details',
{ "files": targetFileIds }
).success( function( data ) {
if ( data.success != 1 ) {
showErrorMessageBox("Failed to enumerate Steam Cloud files. Please try again shortly!");
return;
}
// Pull the data into our internal format
for ( var key in data.files ) {
if ( !data.files.hasOwnProperty( key ) )
continue;
addBuildInfo( data.files[key] );
}
// Actually fill in the data now
populateCloudFiles();
}).fail( function() {
if ( !g_PageUnloading ) {
showErrorMessageBox( "Failed to enumerate Steam Cloud files. Please try again shortly!" );
}
});
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment