您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enables yalb premium buttons
// ==UserScript== // @name yalb Unlocker // @namespace https://greasyfork.org/scripts/400929-yalb-unlocker // @version 0.6 // @description Enables yalb premium buttons // @author Djamana // @match https://*.yalp.io/* //chords/* // @grant none // @run-at document-start //https://tampermonkey.net/documentation.php#_run_at /* * Enables buttons "change speed" without the need to login * Enables buttons "loop", "transpose +/-", "Download MIDI", "tuner" without the need for premium * "Download PDF", and Upload mp3 is currently not working How does this work technically: Well nearly all of the yalb-premium functionality is already there, what blocks it from been used is that the buttons at the UI (html-page) don't have the correct IDs or Class attribute. So later yalb just don't attach the corresponding handler to it. So the main mission here is the restore correct IDs or class attributes before yalb'S document_ready() event handler is executed. Hints for dealing with yalb.min.js: * search for 'create_google_tag' in the 'formated' JavaScript sources. It will bring you to all first level function of major interest and somehow compensate the missing comment and real function names because of the minified source. Example: create_google_tag("play", "user_id " + yalpB) */ // ==/UserScript== 'use strict'; var appVersion = "0.6" // Testpage: // https://yalp.io/chords/gerhard-schoene-der-laden-efc3 // // Tested with https://www.yalp.io/js/yalp.min.full.js // VERSION: 1.18.0 DATE: 2015-09-05 // // History // 0.6 Mai 2020 // * Improved no login required - use of mutation observer to exchanges javascript files on the fly var Conf_chordsContainerHeight = 1280 var Conf_FakeLogin = true // TODO find yalp correct mp3 Upload url ! var Conf_UploadUrl = "//www.yalp.io/submit.php" var Conf_DownloadUrl = "#" //"//www.yalp.io/submit_yalp.php" //https://www.yalp.io/index3.php //https://www.yalp.io/lesson/booking_attempt/slot-id/booktutor.idsong?_=1587026316058 //https://www.yalp.io/lesson/pay_with_stripe/e4 //https://www.yalp.io/store_event //https://www.yalp.io/store_interface_language //https://www.yalp.io/lesson/get_tutors_availability?user%5Btime_zone%5D=Europe%2FBerlin&language=2&instrument_category=guitar&played_instrument_category=guitar&page=1&from_date=2020-04-16%2000:00&to_date=2020-04-16%2023:59&origin=undefined&tutorid=undefined&_=1587026316059 //https://www.yalp.io/searchemail // force to load this jQuery - change to false to use jQuery yalp provide var Conf_jQueryToUse_Url = false //"//ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.js" // Blocks loading addtoany.com Facebook and Co social buttons var Conf_OptFixes_NoSocialbuttons = true var Conf_OptFixes_NoTracking = true // Check if a string contains the given RE-pattern String.prototype.contains = function(RegExpMatchPattern) { var matches = this.match( RegExpMatchPattern ) matches = matches && matches.length return !!matches } ///^\/chords|playlist/ var isChordsUrl = !!document.location.pathname.contains(/^\/chords|playlist/) function otherFixes() { // Beautify try { $("#beats_chords_container").height( Conf_chordsContainerHeight ) $('#dynamic_chords_container').removeClass('hidden') $('#dynamic_demo_container').addClass('hidden') } catch (exception) { console.warn('Error on enlarging chords container', exception); } // Remove 12 Secs delayed message after hitting 'play' // it's triggered only on first play - so // set numbersOfPlay count to a higher value than 0 will disable this // Note: Cookies depends on main.min.js try { //$("#ModalDailyMax").remove() if ( typeof Cookies.get("user_id") == "undefined" ) Cookies.set( "user_id", "DummyUser" ) Cookies.set( "nplay", "1" ) } catch (exception) { console.warn('Error on disabling delayed message after play', exception); } } function removeAds() { // Remove Premium ads try { var PremiumAds = $("a[href$='yalp.io/premium'") PremiumAds.remove() console.log( PremiumAds.length + ' Premium ads deleted.' ); var PremiumAds2 = $("a[href$='yalp.io/pricing'") var MixerOnlyAd = PremiumAds2 && PremiumAds2.parent().parent()// $(".jumbotron:not( [id] )") MixerOnlyAd.remove() } catch (exception) { console.warn('Error on Remove premium ads', exception); } // No Tracking // Overwrite main.min.js ! create_google_tag() with dummy function if (Conf_OptFixes_NoTracking) create_google_tag = my_create_google_tag } function my_create_google_tag(action, userID) { console.log ( "Intercepted TrackingEvent: " + action ) } function RestoreButtonIDs() { //debugger // Extend JQuery alittle ... $.fn.replaceClass = function (pFromClass, pToClass) { return this.removeClass(pFromClass).addClass(pToClass); }; try { // .. and yes we are logged in // so that will unlock the "speed buttons" if (Conf_FakeLogin) { if ( logged == false ) { logged = true is_editor = true //$("#loaded_version") $(".navbar-text") .text("yalb Unlocker: Changes are NOT saved - since FAKE login is active!") // AddYalb_full_js() } } } catch (exception) { console.warn('Error on FakeLogin', exception); } var buttons_locked = $(".notify-premium") //[aria-label] buttons_locked.removeClass("notify-premium") var premiumItemsCount = buttons_locked.length console.log ( premiumItemsCount + " premium buttons found." ) if (premiumItemsCount <= 4 ) { alert( "yalb Unlocker Script - failed. " + "Whops just " + premiumItemsCount + " ?" + "There is something wrong - to less premium items found.") } // KEY: "aria-label" : VALUE: new ID and CLASS Name to be added var newID_Translator = { "Add to Playlist": "add-playlist", "Transpose down" : "transpose-minus" , "Transpose up" : "transpose-plus" , "start tuner" : "start-tuner" , "generate midi" : "generate-midi" , "download-midi" : "generate-midi" , "enable loop" : "loop" , "Print pdf" : "print-grid", "unlimited-pdf-alert" : "print-grid" } var stats_IDsApplied = 0 //debugger buttons_locked.each( function() { try { // Get Attibute "aria-label" or if not exist "data-alert" var button_label = $( this ).attr("aria-label") || $( this ).attr("data-alert") //button_label = buttons_locked.getAttribute("data-alert") //newID = newID.match ("(?:unlimited-)(.*)(?:-alert)") [1] var newID = newID_Translator[ button_label ] if (newID) { // add ID this.id = newID stats_IDsApplied++; // add class $( this ).addClass(newID) } console.log ( (newID ? "#" + stats_IDsApplied + " New" : "NOT APPLIED") + " ID: #" + newID + " <= '" + button_label + "'") } catch (exception) { console.warn('Error on update button ', exception); } }); console.log ( stats_IDsApplied + " button patched.") buttons_locked.removeAttr("data-alert" ) buttons_locked.removeAttr("data-toggle") buttons_locked.removeAttr("data-target") // reenable Upload // Restore Upload-click $(".no-upload-button") .replaceClass( "no-upload-button", "upload-button") // reenable drop mp3 files $('body').addClass("drop") // Recreate Upload button // https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin var form = $("<form >"); //id=fileupload form .append( '<input '+ ' type = "file" '+ ' id = fileupload '+ ' data-url="' + Conf_UploadUrl + '"' + ' name="files[]" '+ '>') $('body').append(form); //.attr("id","fileupload") // Print PDF is not working // that's the yalb - code this will trigger: //$("#print-form [name='token']" ).val(token) //$("#print-form [name='transpose']" ).val(yalpx) //$("#print-form" ).submit() // The form 'print-form' is missing var printForm = $( "<form " + "id = 'print-form' " + "action = '" + Conf_DownloadUrl + "'" + "method = 'post' >" ); //id=fileupload printForm .append('<input type="button" name="token">') .append('<input type="button" name="transpose">'); "submit_yalp.php" $('body').append(printForm); // $('[aria-label="Print pdf"]') // .addClass("print-grid") // Enable Tuner Handler // var tuner = document.getElementById("start-tuner")//"start-tuner") // console.log( tuner.id ); // debugger //tuner.addEventListener("click", yalpza ) // Enable Midi-Download // must satisfy $(".generate-midi") to match with yalb handler ".click(function() {..." // Not needed anymore since now it's also handled by the 'ID_Translator' above // $('[aria-label="generate midi"]') // .addClass("generate-midi") // $('[aria-label="start tuner"]') // .attr("name","transform") // it is important to trigger document_ready handler of yalb which will connect eventhandler to the buttons // if (!$(document).hasClass("ready")) { // $(document).triggerHandler("ready"); // $(document).addClass("ready") // } } /////////////////////////// // RestoreHandlers // Purposes: // some yalb bugfixing function RestoreHandlers () { //Enable Tuner Handler // document.getElementById("start-tuner").addEventListener("click", yalpza) $("button#start-tuner").click(yalpza) // Note that there are 2 Buttons - one is hidden in the "..." Menu (there is transpose and speed) $(".navbar-text") .text("yalb Unlocker " + appVersion) } /////////////////////////// // M A I N loader // Purposes: // * Run RestoreButtonIDs ( to restore/set correct GUI ID ) // BEFORE yalb document_ready() // * Some Yalb Bugfixing ( start-Tuner handler is not set correct) function Main_JQueryReady() { // That will be called when the document is ready... //$( document ).ready(function() { //$( RestoreHandlers ) //$(document).on("ready", RestoreButtonIDs) $( document ).ready( (event) => { // console.log( "document loaded" ); // Restore Buttons IDs and Classes for premium items // .. so that yalb will install most of the handler in its document_ready() event handler if (isChordsUrl) { RestoreButtonIDs() otherFixes() } removeAds() }); $( window ).on( "load", (event) => { console.log( "window loaded" ); RestoreHandlers(); }); $( window ).on( "DOMContentLoaded", (event) => { console.log('DOM fully loaded and parsed'); }); } /////////////////////////// // liteToFull // Hook loading js and css files // and do manipulation to it (exchange, drop...) function liteToFull( searchPattern, attrib, replaceWith, postfix ) { new MutationObserver( ( mutations , observer ) => { //mutations.forEach( (mutation) => { // console.log( mutation.target ); //}); // let script = mutations[0].addedNodes[0] // if ( script.src.match("addtoany.com")!==null ) script.remove() var tmp (tmp = document.querySelector( "script[src*='addtoany.com']" ) ) && tmp.remove() const yalp_lite = document.querySelector( "[" + attrib + "$='" + searchPattern + "']" );//'script[src*="jquery"]'); if (yalp_lite) { var yalp_url = yalp_lite[attrib] var yalp_full = yalp_url.replace( replaceWith , replaceWith + postfix ) yalp_lite[attrib] = yalp_full console.log ( "NEW " + attrib + " '" + yalp_full + "' <= '" + yalp_url + "'" ) //yalp_lite.remove(); // We've done what we needed to do, no need for the MutationObserver anymore: observer.disconnect(); } }) .observe( document.documentElement , // target ( Type: Node ) { childList: true, subtree: true, target: "script" } // options ( Type: MutationObserverInit-Object) );// ( other option: attributes[OldValue] ,characterData[OldValue], attributeFilter) } /////////////////////////// // M A I N loader // Purposes: // * Exchange js and css files for full version // * Run Main when Jquery is ready (function() { // debugger /* let script ; script = document.createElement('script'); script.src = "//www.yalp.io/js/yalp.min.full.js"; document.body.appendChild(script); // execute the script */ // Load full version liteToFull( "yalp.min.js" , "href", ".min.", "full." ) liteToFull( "yalp.min.js" , "src", ".min.", "full." ) liteToFull( "style.min.css" , "href", ".min.", "full." ) // No Ads liteToFull( "ads.min.js" , "src", ".min.", "" ) // Anti-blocker disable var tmp = document.querySelector("head") tmp && tmp.setAttribute("id","yalp-FfCUXEjbzHqO") // in case th first pattern changed the following will break Anti-blocker dectection script tmp = document.querySelector('#ModalAdUnblock') tmp && tmp.remove() // Wait for jquery let attrib = "src" var run = false new MutationObserver( ( mutations , observer ) => { if (run) { Main_JQueryReady() // We've done what we needed to do, no need for the MutationObserver anymore: observer.disconnect(); } const jQuery = document.querySelector( 'script[' + attrib + '*="jquery"]'); if (jQuery) { // Replace jQuery with other one ? if (Conf_jQueryToUse_Url) { let jQuery = jQuery[attrib] jQuery[attrib] = Conf_jQueryToUse_Url } run = true } }) .observe( document.documentElement, { childList: true, subtree: true } ); }) ();