AnimeWorld Scrobbling

Segna automaticamente gli episodi visualizzati su Trakt.TV

目前為 2020-04-21 提交的版本,檢視 最新版本

// ==UserScript==
// @name         AnimeWorld Scrobbling
// @namespace    https://www.pizidavi.altervista.org/
// @description  Segna automaticamente gli episodi visualizzati su Trakt.TV
// @author       pizidavi
// @version      1.3.2
// @copyright    2020, PIZIDAVI
// @license      MIT
// @homepageURL  https://www.pizidavi.altervista.org/AnimeWoldScrobbling/
// @require      https://greasyfork.org/scripts/401626-notify-library/code/Notify%20Library.js
// @include      https://*.animeworld.*/watch/*
// @connect      https://api.trakt.tv/
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_xmlhttpRequest

// ==/UserScript==

(function($) {
    'use strict';

    // USER INFO
    const CLIENT_ID = 'ENTER_CLIENT_ID';
    const ACCESS_TOKEN = 'ENTER_ACCESS_TOKEN';
    const EXPIRES = 'ENTER_EXPIRES_DATE';

    // SETTINGS
    const SHOW_HELPER = true;
    const AUTO_NEXT_EPISODE = true;


    /* ----------- CODE ----------- */
    const css = '#body .sidebar { float: right; width: 300px; position: relative; z-index: 1; }';
    const template = '<div id="trakt" class="sidebar"><div class="widget simple-film-list"><div class="widget-title"><div class="title">Trakt</div></div><div class="widget-body"><div class="row" style="margin-bottom:1em;"><div class="col-sm-21"><button class="btn btn-primary btn-block" id="watched">Episodio Visto</button></div><div class="col-sm-3"><input type="checkbox" id="autoNext" style="margin-top:10px;margin-left:-5px;" title="Prossimo episodio automatico"></div></div><div class="row"><div class="col-sm-11"><input type="text" class="form-control" placeholder="Trakt Slug"><small id="helper" style="display:none;margin:0.3em 0px -5px 0.5em;"><a href="https://www.pizidavi.altervista.org/AnimeWoldScrobbling/#trakt" target="_blank" style="color:grey;">Dove lo trovo?</a></small></div><div class="col-sm-6"><input type="number" class="form-control" value="1" min="0" placeholder="Season"></div><div class="col-sm-6"><button class="btn btn-success">Salva</button></div></div></div></div></div>';


    const AnimeID = getAnimeID();
    var Trakt = GM_getValue(AnimeID, {});
    var section = $(template);

    GM_addStyle(css);
    $('#body #body-container').append(section);

    if(!CLIENT_ID || !ACCESS_TOKEN || !EXPIRES) {
        section.find('div.widget-body').html('Dati Trakt mancanti. Segui la <a href="https://www.pizidavi.altervista.org/AnimeWoldScrobbling/" target="_blank">guida</a>');
        return;
    }
    if(new Date() >= new Date(EXPIRES)) {
        section.find('div.widget-body').html('Access Token Trakt Scaduto');
        return;
    }
    if(AnimeID == undefined) {
        section.find('div.widget-body').html('Errore. AnimeID non trovato');
        return;
    }

    section.find('input[type="text"]').val(Trakt.slug);
    section.find('input[type="number"]').val((Trakt.season || '1'));
    if(AUTO_NEXT_EPISODE)
        section.find('input[type="checkbox"]').attr('checked', '');
    if(SHOW_HELPER)
        section.find('#helper').css('display', 'block');

    section.find('button.btn:not(#watched)').on('click', function() {
        var title = $('#main div.widget.info div.info > div.head h2').text();
        var slug = $(this).parent().parent().find('input[type="text"]').val();
        var season = $(this).parent().parent().find('input[type="number"]').val();

        if(slug != '' && season != '') {
            Trakt.title = title.trim();
            Trakt.slug = slug.trim();
            Trakt.season = season;
            GM_setValue(AnimeID, Trakt);

            section.find('button#watched').removeAttr('disabled');

            new Notify({
                text: 'Dati salvati',
                type: 'success'
            }).show();
        } else {
            new Notify({
                text: 'Completa tutti i campi',
                type: 'warn'
            }).show();
        }
    });

    if(Trakt.slug == undefined || Trakt.season == undefined) {
        section.find('button#watched').attr('disabled', '');
    }
    $('button#watched').on('click', function() {
        var _this = $(this);
        var episode = $('div.server ul a.active').attr('data-base');
        if(Trakt.slug == undefined || Trakt.season == undefined || episode == undefined) {
            new Notify({
                text: 'Errore',
                type: 'error'
            }).show();
            return;
        }
        _this.attr('disabled', '');

        var joData = {
            'shows': [
                {
                    'ids': {
                        'slug': Trakt.slug,
                    },
                    'seasons': [
                        {
                            'number': parseInt(Trakt.season),
                            'episodes': [
                                {
                                    'watched_at': new Date().toJSON(),
                                    'number': parseFloat(episode)
                                }
                            ]
                        }
                    ]
                }
            ]
        };
        request(joData, function(data) {
            if(data.added.episodes > 0) {
                new Notify({
                    text: 'Episodio '+episode+' salvato',
                    type: 'success'
                }).show();

                if(AUTO_NEXT_EPISODE || section.find('#autoNext').prop('checked'))
                    $('#controls > div.prevnext[data-value="next"]').click();
            } else {
                new Notify({
                    text: 'Errore. Episodio non trovato',
                    type: 'error'
                }).show();
            }
            _this.removeAttr('disabled');
        });
    });
    $(document).on('click', '#controls > div.userbookmark > ul > li:nth-child(2), #controls > div.userbookmark > ul > li:nth-child(7)', function() {
        var deleted = deleteOne(AnimeID);
        if(deleted) {
            section.find('input[type="text"]').val('');
            section.find('input[type="number"]').val('1');
            section.find('button#watched').attr('disabled', '');
            Trakt = {};

            new Notify({
                text: 'Dati Trakt rimossi',
                type: 'success'
            }).show();
        }
    });


    // Functions
    function request(data, success) {
        console.log('start');
        var r = new XMLHttpRequest();
        r.open('POST', 'https://api.trakt.tv/sync/history');

        r.setRequestHeader('Content-Type', 'application/json');
        r.setRequestHeader('Authorization', 'Bearer '+ACCESS_TOKEN);
        r.setRequestHeader('trakt-api-version', '2');
        r.setRequestHeader('trakt-api-key', CLIENT_ID);

        r.onreadystatechange = function () {
            if (this.readyState === 4 && this.status == 201) {
                success(JSON.parse(this.responseText));
            }
        };
        r.send(JSON.stringify(data));
    }

    function getAnimeID() {
        var url = location.pathname;
        var start = url.indexOf('.')+1;
        var end = start + (url.substring(start).indexOf('/') >= 0 ? url.substring(start).indexOf('/') : url.substring(start).length);
        return url.substring(start, end) || undefined;
    }

    function deleteOne(key) {
        if(GM_listValues().includes(key)) {
            GM_deleteValue(key);
            return true;
        } else {
            return false;
        }
    }
    function deleteAll() {
        GM_listValues().forEach(function(key) {
            GM_deleteValue(key);
        });
        return true;
    }

})(jQuery);