getSpecialsSSG

Create a ShoeBot !specials list

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         getSpecialsSSG
// @namespace    none
// @version      2021.09.26.2340
// @description  Create a ShoeBot !specials list
// @author       MagentaRV
// @match        http://www.ddo.com/en/news/ddo-chronicle-issue-*
// @match        https://www.ddo.com/en/news/ddo-chronicle-issue-*
// @match        http://www.lotro.com/en/game/articles/lotro-beacon-issue-*
// @match        https://www.lotro.com/en/game/articles/lotro-beacon-issue-*
// @grant        none
// ==/UserScript==

( function() {

    // objOptions = {                   trim: 'false/start/end/true',
    //     nbsp: 'false/replacement/true', b: 'false/replacement/true',
    //     i: 'false/replacement/true',    u: 'false/replacement/true',
    //     span: 'false/replacement/true', a: 'false/replacement/true' }
    function parseHTMLtoDiscord( htmlString, objOptions = {} ) {
        var rxpA = new RegExp( '<a href="((?:https?|mailto):(?:\/\/)?(?:[^"]*?))"(?:.*?)>(.*?)<\/a>', 'g' );
        var rxpB = new RegExp( '<\/?(b|strong)(?:.*?)>', 'gi' );
        var rxpI = new RegExp( '<\/?(i|emphasis)(?:.*?)>', 'gi' );
        var rxpSpan = new RegExp( '<\/?span(?:.*?)>', 'gi' );
        var rxpU = new RegExp( '<\/?u(?:.*?)>', 'gi' );
        switch ( objOptions.trim ) {// Options are false to skip, start, end, or -default- both
            case false: break;
            case 'start': htmlString = htmlString.trimStart(); break;
            case 'end': htmlString = htmlString.trimEnd(); break;
            default: htmlString = htmlString.trim();
        }
        switch ( objOptions.nbsp ) {// Options are false to skip, text to replace &nbsp; with, or -default- a plain space
            case false: break;
            default: htmlString = htmlString.replace( /&nbsp;/g, ( typeof objOptions.nbsp === 'string' ? objOptions.nbsp : ' ' ) );
        }
        switch ( objOptions.b ) {// Options are false to skip, text to replace bold tag with, or -default- **
            case false: break;
            default: htmlString = htmlString.replace( rxpB, ( typeof objOptions.b === 'string' ? objOptions.b : '**' ) );
        }
        switch ( objOptions.i ) {// Options are false to skip, text to replace italic tag with, or -default- *
            case false: break;
            default: htmlString = htmlString.replace( rxpI, ( typeof objOptions.i === 'string' ? objOptions.i : '*' ) );
        }
        switch ( objOptions.u ) {// Options are false to skip, text to replace underline tag with, or -default- __
            case false: break;
            default: htmlString = htmlString.replace( rxpU, ( typeof objOptions.u === 'string' ? objOptions.u : '__' ) );
        }
        switch ( objOptions.span ) {// Options are false to skip, text to replace span tag with, or -default- strip the span
            case false: break;
            default: htmlString = htmlString.replace( rxpSpan, ( typeof objOptions.span === 'string' ? objOptions.span : '' ) );
        }
        switch ( objOptions.a ) {// Options are false to skip, text to replace anchor tag with, or -default- [link text](<link href>)
            case false: break;
            default: htmlString = htmlString.replace( rxpA, ( typeof objOptions.a === 'string' ? objOptions.a : '[$2](<$1>)' ) );
        }
        return htmlString;
    }
// Define which game we're parsing data for
    var strGame = document.URL.replace( /https?:\/\/(?:www\.)?/i, '' );
    strGame = strGame.slice( 0, strGame.indexOf( '.' ) ).toLowerCase();

// Initialize variables
    var now = new Date( document.querySelector( 'time.submitted.pretty' ).title ),
        today = now,
        published = now,
        aWeekFromNow = new Date( now.getFullYear(), String( now.getMonth() ).padStart( 2, '0' ), String( now.getDate() + 7 ).padStart( 2, '0' ) ),
        author = '',
        sSotW = document.querySelectorAll( 'p.rtecenter a img' ),
        IMGsS = sSotW[ sSotW.length - 1 ].src,
        SSdesc = parseHTMLtoDiscord( sSotW[ sSotW.length - 1 ].closest( 'p' ).nextElementSibling.childNodes[ 0 ].innerHTML, { trim: false } ),
        InTheNews = [],
        freebieLinks = {},
        rowFreebie = [],
        arrSalesFree = [],
        strSaleName = '',
        strSalePercent = '',
        arrSalesVal = [],
        arrSaleDates = [],
        objSaleDates = {},
        arrBonusDays = [],
        objBonusDays = {},
        arrBonusDaysVal = [],
        strWeeklyCoupon = '',
        arrWeeklyCoupon = [],
        arrFreebieDates = [],
        objFreebieDates = {},
        strFreebieCode = '',
        strFreebieName = '',
        strFreebieLink = '',
        intFreebieQuantity = 0,
        strFreebieWeek = '';
    if ( strGame === 'ddo' ) {
        var chronicleSections = [];
// Create an object of possible freebies links
        freebieLinks = {
            'unknown': 'https://ddowiki.com/index.php?title=Special:Search&go=Go&search=',
        };
    } else {
        var beaconSections = [];
// Create an object of possible freebies links
        freebieLinks = {
            'unknown': 'https://lotro-wiki.com/index.php?title=Special:Search&go=Go&search=',
            '+5% Attack Damage x25 (90 minutes)': 'https://lotro-wiki.com/index.php/LOTRO_Store#Damage',
            '+5 Hope Boost': 'https://lotro-wiki.com/index.php/LOTRO_Store#Hope',
            '+20% Mount Speed (90 minute) boost': 'https://lotro-wiki.com/index.php/Item:%2B20%25_Mount_Speed_%2890_Min%29',
            '100% XP Boost (1 hour)': 'https://lotro-wiki.com/index.php/Item:Tome_of_Extraordinary_Experience_%28100%29',
//            '100% Mark Acquisition (90 minute) boost': '',// NO LINK
            'Dye: Crimson': 'https://lotro-wiki.com/index.php/Item:Crimson_Dye',
            'Dye: Ered Luin Blue': 'https://lotro-wiki.com/index.php/Item:Ered_Luin_Blue_Dye',
            'Landscape Soldier Token': 'https://lotro-wiki.com/index.php/Item:Landscape_Soldier_Token',
            'Morale Bubble Potion': 'https://lotro-wiki.com/index.php/Item:Morale_Bubble_Potion',
            'Rejuvenation Potion x5': 'https://lotro-wiki.com/index.php/Item:Rejuvenation_Potion',
            'Skill and Slayer Deed Boost': 'https://lotro-wiki.com/index.php/Item:Slayer_and_Skill_Deed_Boost_%2890_min%29',
            'Slayer Deed Accelerator (60 minutes)': '',
            'Universal Ingredient Pack': 'https://lotro-wiki.com/index.php/Item:Universal_Ingredient_Pack',
            'Universal Solvent': 'https://lotro-wiki.com/index.php/Item:Universal_Solvent'
        }
    }

    function parseDates( dateString ) {
        let startDate = dateString.slice( ( dateString.indexOf( ', ' ) === -1 ? ( dateString.indexOf( 'Now' ) === -1 ? dateString.indexOf( ' through ' ) : 0 ) : dateString.indexOf( ', ' ) + 2 ), dateString.indexOf( ' through ' ) ).trim();
        if ( startDate.match( /now/i ) ) { startDate = startDate.toLowerCase(); }
        if ( startDate.indexOf( 'starting ' ) !== -1 ) {
            let arrDate = startDate.match( /starting (\d?\d):\d\d ([AP])M Eastern \((-[45]) GMT\) on (January|February|March|April|May|June|July|August|September|October|November|December) (\d?\d)(?:st|nd|rd|th) and running/ );
            startDate = arrDate[ 4 ] + ' ' + arrDate[ 5 ].padStart( 2, '0' ) + ', ' + ( new Date( now ) ).getFullYear() + ' ' + ( ( parseInt( arrDate[ 1 ] ) + ( arrDate[ 2 ] === 'A' ? 0 : 12 ) ) % 24 ) + ':00:00';
            startDate = ( new Date( startDate ) );
        }
        startDate = ( startDate === 'now' || startDate === '' ? now : ( startDate instanceof Date && !isNaN( startDate.valueOf() ) ? startDate.valueOf() : startDate + ', ' + ( new Date() ).getFullYear() ) );
        let endDate = dateString.match( /(January|February|March|April|May|June|July|August|September|October|November|December) (\d?\d)(?:st|nd|rd|th)/ );
        if ( !endDate ) { endDate = aWeekFromNow.valueOf(); }
        else { endDate = endDate[ 1 ] + ' ' + endDate[ 2 ].replace( /(st|nd|rd|th)[\.!:]/, '' ).padStart( 2, '0' ) + ', ' + ( new Date() ).getFullYear(); }
        return [ new Date( startDate ), new Date( endDate ) ];
    }

// Populate variables depending on which game
    if ( strGame === 'ddo' ) {
        chronicleSections = document.getElementsByTagName( 'h1' );
        InTheNews = chronicleSections[ ( chronicleSections.length - 1 ) ].nextElementSibling.nextElementSibling.children;
    } else {
        author = document.querySelector( 'span.news.author' ).innerText.replace( 'By ', '' );
        beaconSections = document.getElementsByTagName( 'h3' );
        InTheNews = beaconSections[ ( beaconSections.length - 1 ) ].nextSibling.nextSibling.children;
    }

        arrBonusDays = Array.from( InTheNews ).splice( 0, ( Array.from( InTheNews ).length - 2 ) );
        arrBonusDays.forEach( ( bonusDay, i ) => {
            bonusDay = parseHTMLtoDiscord( bonusDay.children[ 0 ].innerHTML );
            let strMatchStart = bonusDay.match( new RegExp( '(Bonus Days brings? you )' ) );
            strMatchStart = ( strMatchStart ? strMatchStart[ 0 ] : '' );
            let intBonusDayStart = bonusDay.indexOf( strMatchStart );
            let thisBD = bonusDay.slice( ( intBonusDayStart === -1 ? 0 : intBonusDayStart ), bonusDay.indexOf( ', ' ) ).replace( strMatchStart, '' );
            if ( thisBD.indexOf( ' through ' ) !== -1 ) { thisBD = thisBD.slice( 0, thisBD.indexOf( ' through ' ) ); }
            if ( bonusDay.lastIndexOf( '!' ) === bonusDay.length ) { thisBD += '!'; }
            else { thisBD += bonusDay.slice( bonusDay.lastIndexOf( '!' ) ); }
            let arrBonusDates = parseDates( bonusDay );
            let objBonusDates = { start: arrBonusDates[ 0 ], end: arrBonusDates[ 1 ] };
            if ( intBonusDayStart !== -1 ) { objBonusDays[ i ] = { name: thisBD, dates: objBonusDates }; }
        } );
        arrSalesFree = InTheNews[ ( InTheNews.length - 2 ) ];
        strSaleName = parseHTMLtoDiscord( arrSalesFree.children[ 0 ].children[ 0 ].innerHTML );
        strSalePercent = arrSalesFree.children[ 0 ].innerText.replace( strSaleName, '' ).match( /(\d+%)/ )[ 1 ];
        arrSalesVal = Array.from( arrSalesFree.children[ 1 ].children );
        arrSalesVal.forEach( ( item, i ) => { arrSalesVal[ i ] = item.innerText; } );
        let tmpSale = arrSalesVal.pop();
        arrSaleDates = parseDates( tmpSale );
        objSaleDates = { start: arrSaleDates[ 0 ], end: arrSaleDates[ 1 ] };
        rowFreebie = parseHTMLtoDiscord( InTheNews[ ( InTheNews.length - 1 ) ].children[ 0 ].innerHTML );
        strFreebieName = rowFreebie.replace( /\*\*/g, '' ).trim().slice( 0, strFreebieName.indexOf( ' with the Coupon Code' ) );
        strFreebieName = strFreebieName.slice( strFreebieName.indexOf( ' gets you a free ' ) ).replace( ' gets you a free ', '' );
        intFreebieQuantity = ( strFreebieName.match( / x([\d]+)/ ) ? parseInt( strFreebieName.match( / x([\d]+)/ )[ 1 ] ) : 1 );
        strFreebieLink = ( Object.keys( freebieLinks ).indexOf( strFreebieName.replace( / x([\d]+)/, '' ) ) === -1 ? freebieLinks.unknown + encodeURI( strFreebieName.replace( ' x' + intFreebieQuantity, '' ) ) : freebieLinks[ strFreebieName.replace( / x([\d]+)/, '' ) ] );
        strFreebieCode = '**' + rowFreebie.slice( rowFreebie.indexOf( 'Coupon Code&nbsp;' ), rowFreebie.indexOf( ', now through ' ) ).replace( 'Coupon Code&nbsp;', '' ) + '**';
        if ( strFreebieCode === '****' ) { strFreebieCode = rowFreebie.slice( rowFreebie.indexOf( 'Coupon Code ' ), rowFreebie.indexOf( ', now through ' ) ).replace( 'Coupon Code ', '' ); }
        arrFreebieDates = parseDates( rowFreebie );
        objFreebieDates = { start: arrFreebieDates[ 0 ], end: arrFreebieDates[ 1 ] };
        strFreebieWeek = objFreebieDates.start.toLocaleDateString( 'en-US', { month: 'short', day: '2-digit' } ) + ' - ' + objFreebieDates.end.toLocaleDateString( 'en-US', { month: 'short', day: '2-digit' } );

// Hand validate all components and make any needed adjustments
    /* Do the thing. */

// Create our object
    var objSpecials = {
        URI: document.URL,
        image: document.getElementsByClassName( 'news content' )[ 0 ].querySelector( 'img' ).getAttribute( 'src' ).replace( 'https://', 'http://' ),
        author: ( strGame === 'ddo' ? '*unknown*' : author ),
        pubDate: published,
        sSotW: {
            img: IMGsS,
            desc: SSdesc
        },
        bonusDays: objBonusDays,
        freebie: {
            dates: objFreebieDates,
            code: strFreebieCode,
            item: {
                name: strFreebieName,
                link: strFreebieLink
            },
            quantity: intFreebieQuantity,
            week: strFreebieWeek
        },
        sales: {
            name: strSaleName,
            dates: objSaleDates,
            percent: strSalePercent,
            value: arrSalesVal
        }
    }

    console.log( '%o', objSpecials );
    console.info( '%s', JSON.stringify( objSpecials ) );
} )();