Skeb Price Sorter

Adds a option to sort skeb users by price.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Skeb Price Sorter
// @namespace    http://tampermonkey.net/
// @version      0.4.0
// @description  Adds a option to sort skeb users by price.
// @author       Zappo
// @match        https://*.skeb.jp/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=skeb.jp
// @grant        GM_xmlhttpRequest
// @grant        GM.xmlHttpRequest
// @grant        GM_getValue
// @grant        GM.getValue
// @grant        GM_setValue
// @grant        GM.setValue
// @grant        GM_listValues
// @grant        GM.listValues
// @grant        GM_deleteValue
// @grant        GM.deleteValue
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    var token = localStorage.getItem('token');

    function has_price(element) {
        return element.querySelector('.sph-price');
    }

    function get_price_uncached(user, callback) {
        GM.xmlHttpRequest({
            url: 'https://skeb.jp/api/users/' + user,
            headers: {
                'Authorization': 'Bearer ' + token
            },
            onload: function(response) {
                try {
                    var data = JSON.parse(response.responseText);
                    var price = data.skills.filter(skill => skill.genre === 'art')[0].default_amount;
                    response.context(price);
                    GM.setValue(user, price).then(() => console.log("saving price for " + user), () => console.log("failed to save price for " + user));
                } catch (error) {
                    console.log('Fetch price error: ' + error);
                    console.log(response.responseText);
                }
            },
            context: callback
        });
    }

    function get_price(user, element, callback) {
        if (has_price(element)) {
            return;
        }
        GM.getValue(user).then(value => {
          if (value !== null && value !== undefined) {
              console.log("using cached price " + value + " for " + user);
              callback(value);
          } else {
              get_price_uncached(user, callback);
          }
        }, () => {
            get_price_uncached(user, callback);
        });
    }

    function add_price_to_user_list(element, price) {
        var price_element = document.createElement('div');
        price_element.textContent = price;
        price_element.classList.add('title', 'is-7', 'sph-price');
        price_element.style.color = 'red';
        element.querySelector('.title').parentElement.querySelector('.image').append(price_element);
    }

    function add_price_to_profile_table(element, price) {
        var price_row = document.createElement('tr');
        price_row.classList.add('sph-price');
        var price_td1 = document.createElement('td');
        price_td1.textContent = 'Artwork (past price)';
        price_row.append(price_td1);
        var price_td2 = document.createElement('td');
        price_td2.textContent = price;
        price_row.append(price_td2);
        element.querySelector('table tbody').prepend(price_row);
    }

    function get_for_all() {
        Array.from(document.querySelectorAll("a[href^='/@'][aria-label]"))
            .filter(el => !has_price(el))
            .forEach(el => get_price(el.href.substring(el.href.indexOf('@') + 1), el, price => add_price_to_user_list(el, price)));
    }

    function get_current_user_price(table) {
        var user_name = window.location.pathname.replace('/@', '');
        get_price(user_name, table, price => add_price_to_profile_table(table, price));
    }

    function get_element_price(element) {
        try {
            return parseInt(element.querySelector('.sph-price').textContent);
        } catch (error) {
            return Infinity;
        }
    }

    function sort_users() {
        var element = document.querySelector('.columns.has-cards');
        if (!element) {
            return;
        }
        Array.from(element.children)
            .sort((a, b) => get_element_price(a) - get_element_price(b))
            .forEach((el, i) => (el.style.order = i));
    }

    function create_button(text, action) {
        var button = document.createElement('button');
        button.classList.add('button', 'is-primary', 'is-fullwidth', 'sph-buttom');
        button.textContent = text;
        button.onclick = action;
        return button;
    }

    function clear_cache() {
        GM.listValues().then(keys => {
            console.log(keys);
            keys.forEach(key => GM.deleteValue(key));
        });
    }

    function add_sort_buttons() {
        var element = document.querySelector('.creatorSort');
        if (!element || element.parentElement.querySelector('.sph-buttom')) {
            return;
        }
        element.parentElement.append(create_button('Get prices', get_for_all));
        element.parentElement.append(create_button('Sort users', sort_users));
        element.parentElement.append(create_button('Clear cache', clear_cache));
    }

    function add_past_price_button() {
        if (!window.location.pathname.startsWith('/@')) {
            return;
        }
        var button = Array.from(document.querySelectorAll('.button'))
            .filter(el => el.textContent === 'Notify on seeking started' || el.textContent === 'Notification reserved')
            .filter(el => !el.parentElement.querySelector('.sph-buttom'));
        if (!button.length) {
            return;
        }
        button = button[0];
        button.parentElement.append(create_button('Get past price', () => get_current_user_price(button.parentElement.parentElement.parentElement)));
    }

    function add_button() {
        add_sort_buttons();
        add_past_price_button();
    }

    function add_observer() {
        var body = document.body;
        var observer = new MutationObserver(mutations => add_button());
        observer.observe(body, {childList: true, subtree: true});
    }

    add_observer();
})();