NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Freesound Moderation Helper // @namespace http://qubodup.net/ // @version 0.9 // @description autoplay freesound moderation sounds upon clicking their name in your moderation queue // @author qubodup // @copyright 2018-2020, qubodup (https://openuserjs.org/users/qubodup // @license MIT // @match https://freesound.org/tickets/moderation/assigned/* // @grant none // ==/UserScript== // This is from https://openuserjs.org/scripts/qubodup/Freesound_Moderation_Helper /* Changelog - 0.9 pre add bg color to selected sounds, matching current decision; Composition quickmod button added, taller [note: I'm not sure what this changelog means. I'm reading this years after but who cares they now update the offical styling it seems at least this way my CSS can be copied] - 0.8 Recording button added; license indicator (cheap for now, might make it nicer later) - 0.7 add select all accepted link; shorten "select all" text; add margin to decision buttons; add color to decision buttons; onclick decision buttons; if #moderation-queue textarea height 80px, set to 160px; code cleanup; decision radio buttons create color warning; sort sounds by user, not date; censor button - 0.6 Additional moderation button (device? and silence); works on Firefox now - 0.5 Shortening moderation buttons; adding a moderation button (timeout?); added changelog - 0.4 Elaborate re-styling of the rest of the page to make moderation more efficient (less cluttered) - pre-0.4 see https://github.com/MTG/freesound/issues/1249 ; amongst others: shorten accepted/deferred to a/deferred; color-code a/d rows; convert date to timer; write full name and abbreviate using CSS rather than removing information; highlight picked user's username in queue (in StopWaiting) */ (function() { 'use strict'; //// ONLY RUN CODE ONCE PAGE HAS STARTED LOADING $(document).ready(function(){ //// CSS // style additions $(`<style type='text/css'> #header { height: 30px; width: 950px; } body, #header, #account_nav { background: none !important; } .button, #container { border: none !important; } .sample_player_small { width: 440px; } #sounds_info { overflow-y: auto !important; overflow-x: hidden !important; } #container { padding: 0px; } #ticket_menu { padding: 0px; width: 100%; } #ticket_menu .button.selected { background-color: white; color: #CB3D44; } #ticket_menu li { margin: 0; } #ticket_menu li a { padding: 10px 60px !important; } #ticket_menu li a:hover { background-color: #f3f3f3 !important; } #wrapper, ul#site_nav li, ul#site_nav li a { background: white !important; } #footer_wrapper, #search, #logo, h1 { display: none !important; } #upload_button { width: auto; height: auto; background: none; display: inline; } tr.row-accept.alternate-row-odd { background-color: #dfffdf; } tr.row-accept.alternate-row-even { background-color: #cfffcf; } tr.row-defer.alternate-row-odd { background-color: #ffdfdf; } tr.row-defer.alternate-row-even { background-color: #ffcfcf; } td { background-color: transparent !important; color: inherit !important; border: none; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .mod-selected-row td:nth-child(2) { font-weight: bold; } td:nth-child(2) a { color: black !important; } .mod-selected-row td.selected-user { font-weight: bold; } tr.alternate-row-odd td.selected-user { background-color: #d5f3ff !important; } tr.alternate-row-even td.selected-user { background-color: #d0eeff !important; } td.user { background-color: transparent !important; } td:nth-child(2) { max-width: 190px; } td:nth-child(3) { max-width: 125px; } table#assigned-tickets-table { width: 448px; } #id_action li { background-color: white; padding: 2px; margin-bottom: 6px; } #id_action li:nth-child(1):hover, .decision-approve #moderation-form, .decision-approve #moderation-form #id_action li:nth-child(1), .decision-approve .mod-selected-row td:nth-child(2), .decision-approve .mod-selected-row td:nth-child(4), .decision-approve .mod-selected-row td:nth-child(5) { background-color:lightgreen !important; } #id_action li:nth-child(2):hover, .decision-delete #moderation-form, .decision-delete #moderation-form #id_action li:nth-child(2), .decision-delete .mod-selected-row td:nth-child(2), .decision-delete .mod-selected-row td:nth-child(4), .decision-delete .mod-selected-row td:nth-child(5) { background-color:coral !important; } #id_action li:nth-child(3):hover, .decision-defer #moderation-form, .decision-defer #moderation-form #id_action li:nth-child(3), .decision-defer .mod-selected-row td:nth-child(2), .decision-defer .mod-selected-row td:nth-child(4),.decision-defer .mod-selected-row td:nth-child(5) { background-color:PaleGoldenrod !important; } #id_action li:nth-child(4):hover, .decision-return #moderation-form, .decision-return #moderation-form #id_action li:nth-child(4), .decision-return .mod-selected-row td:nth-child(2), .decision-return .mod-selected-row td:nth-child(4), .decision-return .mod-selected-row td:nth-child(5) { background-color:lightgrey !important; } #id_action li:nth-child(5):hover, .decision-whitelist #moderation-form, .decision-whitelist #moderation-form #id_action li:nth-child(5), .decision-whitelist .mod-selected-row td:nth-child(2), .decision-whitelist .mod-selected-row td:nth-child(4), .decision-whitelist .mod-selected-row td:nth-child(5) { background-color:white !important; } #moderation-decision-form p:nth-child(4), #moderation-form form div:nth-child(3) p:nth-child(4) { float: right; background-color: white; padding: 2px 2px 0px 2px; border: 1px solid white; } #moderation-decision-form p.selected, #moderation-form form div:nth-child(3) p.selected { background-color: pink; border: 1px solid black; } #assigned-tickets-table-wrapper { height: inherit; } #moderation-form form { background-color: inherit; border: none; } #sounds_info { background-color: white; } #select-accepted { font-size: 12px; cursor: pointer; } #moderation_options_ input { margin-bottom: .5em; } #quick-wrong, #quick-illegal, #quick-silent { background-color: coral; } #quick-recording, #quick-composition, #quick-description, #quick-language, #quick-timeout, #quick-tags { background-color: PaleGoldenrod; } #quick-device { background-color: lightgreen; } #censor { color: white !important; } .censored { filter: blur(8px) !important; } .sample_information { border-width: 0px !important; float: inherit !important; display: initial !important; } .sample_information a, .sample_information br, .sample_information span { display: none; } .sample_information img { float: right !important; margin-top: -90px !important; } </style>`).appendTo("head"); //// HEADER AND GENERAL NON-MODERATION STYLE CHANGES // minimize upload button $("#upload_button").html("Upload"); //// MODERATION QUEUE SELECTION BUTTONS // minimize "select all by user even deferred" link and add warning $("#select-all-same-user").html("select user"); $("#select-all-same-user").attr('title', 'warning: selects deferred sounds too'); // add "select all by user but only active" link $("#select-all-same-user-wrapper").after(" | <a id='select-accepted' title='warning: does not deselect selected deferred sounds'>select user accepted</a>"); $("#select-accepted").click(function(){ var selectedUserIds = {}; $('.ticket-check:checked').each(function () { var ticket_id = $(this).data('id'); var user_id = $("#row_" + ticket_id).data('sender-id'); selectedUserIds[user_id] = true; }); if (Object.keys(selectedUserIds).length == 1){ var target_user_id = Object.keys(selectedUserIds)[0]; $('.ticket-check').each(function () { var ticket_id = $(this).data('id'); var t_user_id = $("#row_" + ticket_id).data('sender-id'); var t_user_active = $("#row_" + ticket_id).hasClass('row-accept'); if (t_user_id == target_user_id && t_user_active){ $("#row_" + ticket_id).find('.ticket-check').attr('checked', true); } }); } updateSelectedTickets(); }); //// MODERATION QUEUE DISPLAY OF CONTENT STREAMLINING // constants var TODAY = new Date(); // for each sound ticket $('#assigned-tickets-table-wrapper table#assigned-tickets-table tr').each(function (i, row) { // get ticket id var ticket = $(this).attr("data-messages-url").toString().split("tickets/")[1].split("/')")[0]; // get status ("Accepted" or "Deferred"), trim for safety(?) var status = $(this).children("td:nth-child(5)").text().trim(); // make status strings compact // turn status indicators into ticket links to save additional space // add classes according to status if ( status == "Accepted" ) { $(this).children("td:nth-child(5)").html("<a target='_blank' href='http://freesound.org/tickets/" + ticket + "' title='Accepted ticket'>A</a>"); $(this).addClass('row-accept'); } else if ( status == "Deferred" ) { $(this).children("td:nth-child(5)").html("<a target='_blank' href='http://freesound.org/tickets/" + ticket + "' title='Deferred ticket'>D</a>"); $(this).addClass('row-defer'); } // convert date to days, to save space and sanity var sound_date_array = $(row).children("td:nth-child(4)").text().split("/"); var sound_date = new Date(sound_date_array[2], sound_date_array[1] - 1, sound_date_array[0]); var sound_days = Math.floor((TODAY - sound_date) / 1000 / 60 / 60 / 24); $(this).children("td:nth-child(4)").text(sound_days + "d"); // get username from data-sound-url var username = $(this).attr("data-sound-url").split("people/")[1].split("/")[0]; // replace table username with sourced username to make use of available space $(this).children("td:nth-child(3)").text(username); }); // sort (group) sounds in queue by user, not simply sort by date. // this way, it's less likely to accidentally apply decisions to sounds below the bottom border, // as intuitively the system makes us used to sounds being grouped by user. // store user names in order of ocurence var usersOrder = new Array(); // fill list of user names $('#assigned-tickets-table-wrapper table#assigned-tickets-table tr').each(function (i, row) { var username = $(this).attr("data-sound-url").split("people/")[1].split("/")[0]; if (!usersOrder.includes(username)){ usersOrder.push(username); } }); // for each user usersOrder.forEach(function(name, i) { // debug //console.log(i,name); // track whether user has occured yet or not var nameOccured = false; // track at which index a different name appeared var gapIndex = null; // for each row $('#assigned-tickets-table-wrapper table#assigned-tickets-table tr').each(function (j, row) { // get row's user name var nameRow = $(this).attr("data-sound-url").split("people/")[1].split("/")[0]; // register if current name occurs for first time if (!nameOccured && name == nameRow) { nameOccured = true; } else // if current name has occurred, remember which row had different name first for later swapping if (gapIndex == null && nameOccured && name != nameRow) { gapIndex = j } else // move (don't move deferred rows) if ($(this).hasClass('row-accept') && gapIndex != null && nameOccured && name == nameRow) { $(row).insertBefore($('#assigned-tickets-table-wrapper table#assigned-tickets-table tr')[gapIndex]); // the gap just moved by one gapIndex += 1; } }); }); // re-assign odd/even row classes var odd = true; $('#assigned-tickets-table-wrapper table#assigned-tickets-table tr').each(function (j, row) { $(this).removeClass("alternate-row-odd").removeClass("alternate-row-even"); if(odd) { $(this).addClass("alternate-row-odd"); } else { $(this).addClass("alternate-row-even"); } odd = !odd; }); //// FUNCTION FOR HIGHLIGHTING ROWS WITH SOUNDS BY CURRENT SELECTED USER's SOUND function MarkUser(userId) { // uses sender ID, as different usernames could have same abbreviation (which is used by default) // and user info box has unnecessary load delay $('#assigned-tickets-table-wrapper table#assigned-tickets-table tr').each(function (i, row) { var userNameField = $(this).children("td:nth-child(3)"); var rowUserId = $(this).attr("data-sender-id"); if (userId == rowUserId) { $(userNameField).addClass("selected-user"); $(userNameField).removeClass("user"); } else { $(userNameField).removeClass("selected-user"); $(userNameField).addClass("user"); } }); } // paint selected user without having to click (need to get first item's userId for that) MarkUser($("table tbody tr:nth-child(1)").attr("data-sender-id")); //// FUNCTIONS FOR AUTO-PLAY OF SOUNDS WHEN CLICKING SOUND NAME IN QUEUE function StopWaiting() { $("#sound_0 a.toggle.play")[0].click(); } function StartWaiting() { //console.log("loading"); var loadCheck = setInterval(function(){ if ($("#sound_0 a.toggle.play").length){ //console.log("loaded"); StopWaiting(); clearInterval(loadCheck); } }, 32); } // Let's actually use these functions // sound playback and loading class are controlled by the click event $('#assigned-tickets-table-wrapper table#assigned-tickets-table tr').find('td:nth-child(2) a').bind('click', function(){ StartWaiting(); var userId = $(this).parent().parent().attr("data-sender-id"); MarkUser(userId); }); //// QUICK MODERATION BUTTONS, RADIO BUTTONS, TEXT BOX // Shorten quick moderation button texts $("#moderation_options_ input:nth-child(1)").attr("value", "Tags").attr('id', 'quick-tags'); $("#moderation_options_ input:nth-child(2)").attr("value", "Description").attr('id', 'quick-description'); $("#moderation_options_ input:nth-child(3)").attr("value", "Language").attr('id', 'quick-language'); $("#moderation_options_ input:nth-child(4)").attr('id', 'quick-illegal'); $("#moderation_options_ input:nth-child(5)").attr("value", "Wrong").attr('id', 'quick-wrong'); // Add quick moderation buttons $("#moderation_options_ input:nth-child(1)").before("<input id='quick-device' type='button' class='moderation_text' value='Device' onclick=\"$('#id_message').get(0).value += 'In the future, please write the recording device used, if you can. Thanks for sharing!\\n';\"> "); $("#moderation_options_ input:nth-child(2)").before("<input id='quick-timeout' type='button' class='moderation_text' value='Timeout' onclick=\"$('#id_message').get(0).value += '\\nThis ticket will time out in two weeks.';\"> "); $("#moderation_options_ input:nth-child(6)").before("<input id='quick-silent' type='button' class='moderation_text' value='Silent' onclick=\"$('#id_message').get(0).value += 'Please re-upload the sound without long sections of complete silence in the file.\\n';\"> "); $("#moderation_options_ input:nth-child(3)").before("<input id='quick-recording' type='button' class='moderation_text' value='Recording' onclick=\"$('#id_message').get(0).value += 'Thank you for sharing. Is this your own recording or taken from a website/sound library?\\nIf yours: could you please add to the description what device was used to record it?\\nIf not yours: please let us know from where.';\"> "); $("#moderation_options_ input:nth-child(4)").before("<input id='quick-composition' type='button' class='moderation_text' value='Composition' onclick=\"$('#id_message').get(0).value += 'Thank you for sharing. Is this your own composition or taken from a website/music track/music library?\\nIf yours: could you please briefly add to the description how it was made?\\nIf not yours: please let us know from where.';\"> "); // When clicking decision buttons, resize text box if it's default height (80px) $("#moderation_options_ input").click(function(){ if ($("textarea#id_message").height() == 80){ $("textarea#id_message").height(160); } }); // Use decision radio buttons to change color as a warning function decisionWarning(option) { $("#moderation-queue").removeClass(); switch(option) { case 'Approve' : $("#moderation-queue").addClass("decision-approve"); break; case 'Delete' : $("#moderation-queue").addClass("decision-delete"); break; case 'Defer' : $("#moderation-queue").addClass("decision-defer"); break; case 'Return' : $("#moderation-queue").addClass("decision-return"); break; case 'Whitelist' : $("#moderation-queue").addClass("decision-whitelist"); break; } } // scan standard decision decisionWarning("Approve") // scan decision each time decision radio buttons are pressed $('#id_action input[type=radio][name=action]').change(function(){decisionWarning($(this).val());}); // explicit and mod-only checkboxes selected warnings $("#moderation-decision-form p:nth-child(4) input, #moderation-form form div:nth-child(3) p:nth-child(4) input").change(function(){ if ($(this).is(':checked')) { $(this).parent().addClass('selected'); } else { $(this).parent().removeClass('selected'); } }); //// CENSORE TOGGLE $("#account_nav").append("<a id='censor'>C</a>"); $('#censor').toggle(function () { $("table").addClass("censored"); $("#account_user").addClass("censored"); $("#sounds_info").addClass("censored"); $("#user-annotations-section").addClass("censored"); $("#moderate-form-title-label").addClass("censored"); }, function () { $("table").removeClass("censored"); $("#account_user").removeClass("censored"); $("#sounds_info").removeClass("censored"); $("#user-annotations-section").removeClass("censored"); $("#moderate-form-title-label").removeClass("censored"); }); }); // end document ready })(); // end (function() { which tampermonkey prescribed