//アカウントマネージャ //最初に読むやつ function load() { $("#acct-list").html(""); if (location.search) { var m = location.search.match(/\?mode=([a-zA-Z-0-9]+)\&code=(.+)/); var mode = m[1]; var codex = m[2]; if (mode == "first" && codex == "true") { $("body").addClass("first") } else { } } var prof = localStorage.getItem("prof"); $(".my-prof").attr("src", prof); var name = localStorage.getItem("name"); $("#now-name").text(name); var user = localStorage.getItem("user"); $("#now-user").text(user); var domain = localStorage.getItem("domain"); $(".now-domain").text(domain); var multi = localStorage.getItem("multi"); if (!multi) { var obj = []; } else { var obj = JSON.parse(multi); } if (obj[0]) { if (!obj[0].at) { obj = []; localStorage.removeItem("multi"); } } console.table(obj); var templete; Object.keys(obj).forEach(function (key) { var acct = obj[key]; var list = key * 1 + 1; if (acct.background != "def" && acct.text != "def") { var style = 'style="background-color:#' + acct.background + '; color:' + acct.text + ';"' } else { var style = "" } if (acct.name) { var name = acct.name; } else { var name = acct.user; } templete = '
' + list + '.' + name + '' + escapeHTML(acct.user) + '@' + acct.domain + '
info' + lang.lang_manager_info + 'refresh' + lang.lang_manager_refresh + 'delete' + lang.lang_manager_delete + '
' + lang.lang_manager_color + '
'; $("#acct-list").append(templete); colorpicker(key) }); multisel(); var acctN = localStorage.getItem("acct"); if (!acctN) { localStorage.setItem("acct", 0); var acctN = 0; } //全部チェックアリでいいと思うの $("#linux").prop("checked", true); } //最初に読む load(); support(); //instances.social/instances API function data(domain) { $("#ins-upd").text("Loading..."); $("#ins-add").text("Loading..."); $("#ins-connect").text("Loading..."); $("#ins-toot").text("Loading..."); $("#ins-sys").text("Loading..."); $("#ins-per").text("Loading..."); $("#ins-user").text("Loading..."); $("#ins-ver").text("Loading..."); $("#ins-name").text("Loading..."); $("#ins-prof").attr('src', "../../img/loading.svg"); var start = "https://instances.social/api/1.0/instances/show?name=" + domain; fetch(start, { method: 'GET', headers: { 'content-type': 'application/json', 'Authorization': 'Bearer tC8F6xWGWBUwGScyNevYlx62iO6fdQ4oIK0ad68Oo7ZKB8GQdGpjW9TKxBnIh8grAhvd5rw3iyP9JPamoDpeLQdz62EToPJUW99hDx8rfuJfGdjQuimZPTbIOx0woA5M' }, }).then(function (response) { return response.json(); }).catch(function (error) { todo(error); console.error(error); }).then(function (json) { if (!json.error) { $("#ins-name").text(json.name); $("#ins-upd").text(date(json.checked_at, 'full')); $("#ins-add").text(date(json.added_at, 'full')); $("#ins-connect").text(json.connections); $("#ins-toot").text(json.statuses); $("#ins-sys").text(date(json.updated_at, 'full')); $("#ins-per").text(json.uptime * 100); $("#ins-user").text(json.users); $("#ins-ver").text(json.version); } else { console.error(json.error); } }); var start = "https://" + domain + "/api/v1/instance"; fetch(start, { method: 'GET', headers: { 'content-type': 'application/json', }, }).then(function (response) { return response.json(); }).catch(function (error) { todo(error); console.error(error); }).then(function (json) { if (!json.error) { $("#ins-title").text(json.title); $("#ins-desc").html(json.description); $("#ins-email").text(json.email); $("#ins-toot").text(json.stats.status_count); $("#ins-user").text(json.stats.user_count); $("#ins-ver").text(json.version); $("#ins-prof").attr('src', json.thumbnail); $("#ins-admin").text(escapeHTML(json.contact_account.display_name) + "(" + json.contact_account.acct + ")"); $("#ins-admin").attr("href", "index.html?mode=user&code=" + json.contact_account.username + "@" + domain); } else { console.error(json.error); } }); } //アカウントデータ 消す function multiDel(target) { var multi = localStorage.getItem("multi"); var obj = JSON.parse(multi); //削除確認ダイアログ Swal.fire({ title: lang.lang_manager_logout, text: obj[target]["user"] + "@" + obj[target]["domain"] + lang.lang_manager_confirm, type: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: lang.lang_yesno, cancelButtonText: lang.lang_no }).then((result) => { if (result.value) { Object.keys(obj).forEach(function (key) { var nk = key - 1; //公開範囲(差分のみ) if (key >= target) { var oldvis = localStorage.getItem("vis-memory-" + key); if (oldvis) { localStorage.setItem("vis-memory-" + nk, oldvis); } } //独自ロケール localStorage.removeItem("home_" + key); localStorage.removeItem("local_" + key); localStorage.removeItem("public_" + key); localStorage.removeItem("notification_" + key); //アクセストークンとドメイン、プロフ(差分) if (key > target) { var olddom = localStorage.getItem("domain_" + key); localStorage.setItem("domain_" + nk, olddom); var oldat = localStorage.getItem("acct_" + key + "_at"); localStorage.setItem("acct_" + nk + "_at", oldat); localStorage.setItem("name_" + nk, localStorage.getItem("name_" + key)); localStorage.setItem("user_" + target, localStorage.getItem("user_" + key)); localStorage.setItem("user-id_" + target, localStorage.getItem("user-id_" + key)); localStorage.setItem("prof_" + target, localStorage.getItem("prof_" + key)); } }); //とりあえず消す obj.splice(target, 1); var json = JSON.stringify(obj); localStorage.setItem("multi", json); load(); //カラムデータコンフリクト var col = localStorage.getItem("column"); var oldcols = JSON.parse(col); var newcols = []; Object.keys(oldcols).forEach(function (key) { var nk = key - 1; var oldcol = oldcols[key]; if (target < oldcol.domain) { var newdom = oldcol.domain - 1; } else { var newdom = oldcol.domain; } var type = oldcol.type; //消した垢のコラムじゃないときコピー if (target != oldcol.domain) { var add = { domain: newdom, type: type }; newcols.push(add); } }); var json = JSON.stringify(newcols); localStorage.setItem("column", json); } }) } function multiDel2(target) { var multi = localStorage.getItem("multi"); var obj = JSON.parse(multi); Swal.fire({ title: lang.lang_manager_logout, text: obj[target]["user"] + "@" + obj[target]["domain"] + lang.lang_manager_confirm, type: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: lang.lang_yesno, cancelButtonText: lang.lang_no }).then((result) => { if (result.value) { obj.splice(target, 1); var json = JSON.stringify(obj); localStorage.setItem("multi", json); Object.keys(obj).forEach(function (key) { if (key >= target) { var oldvis = localStorage.getItem("vis-memory-" + key); if (oldvis) { var nk = key - 1; localStorage.setItem("vis-memory-" + nk, oldvis); } } localStorage.removeItem("home_" + key); localStorage.removeItem("local_" + key); localStorage.removeItem("public_" + key); localStorage.removeItem("notification_" + key); refresh(key); }); var col = localStorage.getItem("column"); if (!col) { var obj = [{ domain: 0, type: 'local' }]; localStorage.setItem("card_0", "true"); var json = JSON.stringify(obj); localStorage.setItem("column", json); } else { var cobj = JSON.parse(col); } Object.keys(cobj).forEach(function (key) { var column = cobj[key]; if (column.domain > target) { var nk = key - 1; column.domain = nk; cobj[key] = column; } else if (column.domain == target) { localStorage.removeItem("card_" + tlid); cobj.splice(key, 1); } }); var json = JSON.stringify(column); localStorage.setItem("column", json); load(); } }) } //サポートインスタンス function support() { Object.keys(idata).forEach(function (key) { var instance = idata[key]; if (instance == "instance") { templete = '' + idata[key + "_name"] + '(' + key + ')'; $("#support").append(templete); } }); } //URL指定してポップアップ function login(url) { var multi = localStorage.getItem("multi"); var obj = JSON.parse(multi); if ($('#misskey:checked').val() == "on") { $("#misskey").prop("checked", true); misskeyLogin(url); return; } $("#compt").hide() if ($('#linux:checked').val() == "on") { var red = "urn:ietf:wg:oauth:2.0:oob" } else { var red = 'thedesk://manager'; } localStorage.setItem("redirect", red); var start = "https://" + url + "/api/v1/apps"; var httpreq = new XMLHttpRequest(); httpreq.open('POST', start, true); httpreq.setRequestHeader('Content-Type', 'application/json'); httpreq.responseType = "json"; httpreq.send(JSON.stringify({ scopes: 'read write follow', client_name: "TheDesk(PC)", redirect_uris: red, website: "https://thedesk.top" })); httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response; localStorage.setItem("msky", "false"); var auth = "https://" + url + "/oauth/authorize?client_id=" + json[ "client_id"] + "&client_secret=" + json["client_secret"] + "&response_type=code&scope=read+write+follow&redirect_uri=" + encodeURIComponent(red); localStorage.setItem("domain_tmp", url); localStorage.setItem("client_id", json["client_id"]); localStorage.setItem("client_secret", json["client_secret"]); $("#auth").show(); versionChecker(url) $("#add").hide(); postMessage(["openUrl", auth], "*") if ($('#linux:checked').val() == "on") { } else { postMessage(["sendSinmpleIpc", "quit"], "*") } } } } function versionChecker(url) { var start = "https://" + url + "/api/v1/instance"; fetch(start, { method: 'GET', headers: { 'content-type': 'application/json', }, }).then(function (response) { return response.json(); }).catch(function (error) { todo(error); console.error(error); }).then(function (json) { var version = json.version if (version) { var reg = version.match(/^[0-9]\.[0-9]\.[0-9]/u); if (reg) { reg = reg[0] versionCompat(url, reg, json.title, version) } } }); } function versionCompat(url, ver, title, real) { $("#compt-instance").text(title) $("#compt-ver").text(real) if(~real.indexOf("compatible")){ $("#compt-warn").show() }else{ $("#compt-warn").hide() } $("#compt-list").html("") var start = "../../source/version.json"; fetch(start, { method: 'GET', headers: { 'content-type': 'application/json', }, }).then(function (response) { return response.json(); }).catch(function (error) { todo(error); console.error(error); }).then(function (json) { var complete = false var ct = 0 Object.keys(json).forEach(function (key) { var data = json[key]; if (data) { if (key != ver && !complete) { for (var i = 0; i < data.length; i++) { var e = "" if (i == 0) { e = "(" + key + ")" } $("#compt-list").append('
  • ' + data[i] + e + '
  • ') ct++; e = "" } } else if (!complete) { complete = true } } var lastkey = key }); if (lang.language == "ja" && ct > 0) { $("#compt").show() } }); } //これが後のMisskeyである。 function misskeyLogin(url) { if (!url) { var url = $("#misskey-url").val(); } var start = "https://" + url + "/api/app/create"; var httpreq = new XMLHttpRequest(); httpreq.open('POST', start, true); httpreq.setRequestHeader('Content-Type', 'application/json'); httpreq.responseType = "json"; localStorage.setItem("msky", "true"); httpreq.send(JSON.stringify({ name: "TheDesk(PC)", description: "Mastodon client for PC", permission: [ "account-read", "account-write", "account/read", "account/write", "drive-read", "drive-write", "favorite-read", "favorite-write", "favorites-read", "following-read", "following-write", "messaging-read", "messaging-write", "note-read", "note-write", "notification-read", "notification-write", "reaction-read", "reaction-write", "vote-read", "vote-write", "read:account", "write:account", "read:drive", "write:drive", "read:blocks", "write:blocks", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes" ] })); httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response; misskeyAuth(url, json.secret) } } } function misskeyAuth(url, mkc) { var start = "https://" + url + "/api/auth/session/generate"; var httpreq = new XMLHttpRequest(); httpreq.open('POST', start, true); httpreq.setRequestHeader('Content-Type', 'application/json'); httpreq.responseType = "json"; localStorage.setItem("mkc", mkc) localStorage.setItem("msky", "true"); httpreq.send(JSON.stringify({ appSecret: mkc })); httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response; var token = json.token; $("#auth").show(); $("#code").val(token); $("#add").hide(); $("#misskey").prop("checked", false); localStorage.setItem("domain_tmp", url); postMessage(["openUrl", json.url], "*") } } } //テキストボックスにURL入れた function instance() { var url = $("#url").val(); if (url.indexOf("@") != -1 || url.indexOf("https") != -1) { alert("入力形式が違います。(Cutls@mstdn.jpにログインする場合、入力するのは\"mstdn.jp\"です。)") return false; } login(url); } //コード入れてAccessTokenゲット function code(code) { localStorage.removeItem("redirect") if (!code) { var code = $("#code").val(); $("#code").val(""); } var url = localStorage.getItem("domain_tmp"); localStorage.removeItem("domain_tmp"); if (localStorage.getItem("msky") == "true") { var start = "https://" + url + "/api/auth/session/userkey"; var httpreq = new XMLHttpRequest(); httpreq.open('POST', start, true); httpreq.setRequestHeader('Content-Type', 'application/json'); httpreq.responseType = "json"; httpreq.send(JSON.stringify({ token: code, appSecret: localStorage.getItem("mkc") })); httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response; var i = sha256(json.accessToken + localStorage.getItem("mkc")); var avatar = json["user"]["avatarUrl"]; var priv = "public"; var add = { at: i, name: json["user"]["name"], domain: url, user: json["user"]["username"], prof: avatar, id: json["user"]["id"], vis: priv, mode: "misskey" }; localStorage.setItem("mode_" + url, "misskey") var multi = localStorage.getItem("multi"); var obj = JSON.parse(multi); var target = obj.lengtth; obj.push(add); localStorage.setItem("name_" + target, json["user"]["name"]); localStorage.setItem("user_" + target, json["user"]["username"]); localStorage.setItem("user-id_" + target, json["user"]["id"]); localStorage.setItem("prof_" + target, avatar); var json = JSON.stringify(obj); localStorage.setItem("multi", json); if ($("body").hasClass("first")) { location.href = "index.html" } load(); return; } } return; } else { var start = "https://" + url + "/oauth/token"; var id = localStorage.getItem("client_id"); var secret = localStorage.getItem("client_secret"); var httpreq = new XMLHttpRequest(); httpreq.open('POST', start, true); httpreq.setRequestHeader('Content-Type', 'application/json'); httpreq.responseType = "json"; httpreq.send(JSON.stringify({ grant_type: "authorization_code", redirect_uri: "urn:ietf:wg:oauth:2.0:oob", client_id: id, client_secret: secret, code: code })); httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response; if (json["access_token"]) { $("#auth").hide(); $("#add").show(); getdata(url, json["access_token"]); } } } } } //ユーザーデータ取得 function getdata(domain, at) { var start = "https://" + domain + "/api/v1/accounts/verify_credentials"; fetch(start, { method: 'GET', headers: { 'content-type': 'application/json', 'Authorization': 'Bearer ' + at }, }).then(function (response) { return response.json(); }).catch(function (error) { todo(error); console.error(error); }).then(function (json) { if (json.error) { console.error("Error:" + json.error); M.toast({ html: lang.lang_fatalerroroccured + "Error:" + json.error, displayLength: 5000 }) return; } var avatar = json["avatar"]; //missingがmissingなやつ if (avatar == "/avatars/original/missing.png") { avatar = "../../img/missing.svg"; } if (json["source"]) { var priv = json["source"]["privacy"]; } else { var priv = "public"; } var add = { at: at, name: json["display_name"], domain: domain, user: json["acct"], prof: avatar, id: json["id"], vis: priv, mode: "mastodon" }; var multi = localStorage.getItem("multi"); var obj = JSON.parse(multi); var target = obj.lengtth; obj.push(add); localStorage.setItem("name_" + target, json["display_name"]); localStorage.setItem("user_" + target, json["acct"]); localStorage.setItem("user-id_" + target, json["id"]); localStorage.setItem("prof_" + target, avatar); var json = JSON.stringify(obj); localStorage.setItem("multi", json); if ($("body").hasClass("first")) { location.href = "index.html" } load(); }); } //ユーザーデータ更新 function refresh(target) { var multi = localStorage.getItem("multi"); var obj = JSON.parse(multi); if (obj[target].mode == "misskey") { misskeyRefresh(obj, target, obj[target].domain); return } var start = "https://" + obj[target].domain + "/api/v1/accounts/verify_credentials"; fetch(start, { method: 'GET', headers: { 'content-type': 'application/json', 'Authorization': 'Bearer ' + obj[target].at }, }).then(function (response) { return response.json(); }).catch(function (error) { todo(error); console.error(error); }).then(function (json) { if (json.error) { console.error("Error:" + json.error); M.toast({ html: lang.lang_fatalerroroccured + "Error:" + json.error, displayLength: 5000 }) return; } var avatar = json["avatar"]; //missingがmissingなやつ if (avatar == "/avatars/original/missing.png" || !avatar) { avatar = "./img/missing.svg"; } var ref = { at: obj[target].at, name: json["display_name"], domain: obj[target].domain, user: json["acct"], prof: avatar, id: json["id"], vis: json["source"]["privacy"] }; localStorage.setItem("name_" + target, json["display_name"]); localStorage.setItem("user_" + target, json["acct"]); localStorage.setItem("user-id_" + target, json["id"]); localStorage.setItem("prof_" + target, avatar); obj[target] = ref; var json = JSON.stringify(obj); localStorage.setItem("multi", json); load(); }); } function misskeyRefresh(obj, target, url) { var start = "https://" + url + "/api/users/show"; var httpreq = new XMLHttpRequest(); httpreq.open('POST', start, true); httpreq.setRequestHeader('Content-Type', 'application/json'); httpreq.responseType = "json"; httpreq.send(JSON.stringify({ username: obj[target].user, i: localStorage.getItem("at") })); httpreq.onreadystatechange = function () { if (httpreq.readyState === 4) { var json = httpreq.response; return; var avatar = json["user"]["avatarURL"]; var priv = "public"; var add = { at: json.accessToken, name: json["user"]["name"], domain: url, user: json["user"]["username"], prof: avatar, id: json["user"]["id"], vis: priv }; var multi = localStorage.getItem("multi"); var obj = JSON.parse(multi); var target = obj.lengtth; obj.push(add); localStorage.setItem("name_" + target, json["user"]["name"]); localStorage.setItem("user_" + target, json["user"]["username"]); localStorage.setItem("user-id_" + target, json["user"]["id"]); localStorage.setItem("prof_" + target, avatar); var json = JSON.stringify(obj); localStorage.setItem("multi", json); load(); return; } } } //アカウントを選択…を実装 function multisel() { var multi = localStorage.getItem("multi"); if (!multi) { var obj = []; var json = JSON.stringify(obj); localStorage.setItem("multi", json); } else { var obj = JSON.parse(multi); } var templete; var last = localStorage.getItem("main"); var sel; if (obj.length < 1) { $("#src-acct-sel").html(''); $("#add-acct-sel").html(''); } else { Object.keys(obj).forEach(function (key) { var acct = obj[key]; var list = key * 1 + 1; if (key == last) { sel = "selected"; mainb = '(' + lang.lang_manager_def + ')' var domain = localStorage.getItem("domain_" + key); var profimg = localStorage.getItem("prof_" + key); var domain = localStorage.getItem("domain_" + key); if (!profimg) { profimg = "../../img/missing.svg"; } } else { sel = ""; mainb = "" } templete = ''; $(".acct-sel").append(templete); }); } $('select').formSelect(); } function mainacct() { var acct_id = $("#main-acct-sel").val(); localStorage.setItem("main", acct_id); M.toast({ html: lang.lang_manager_mainAcct, displayLength: 3000 }) } function colorpicker(key) { temp = '
    ' + lang.lang_manager_none + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    '; $("#colorsel_" + key).html(temp); } function coloradd(key, bg, txt) { var col = localStorage.getItem("multi"); var o = JSON.parse(col); var obj = o[key]; obj.background = bg; obj.text = txt; o[key] = obj; var json = JSON.stringify(o); localStorage.setItem("multi", json); if (txt == "def") { $("#acct_" + key).attr("style", "") } else { $("#acct_" + key).css('background-color', '#' + bg); if (txt == "black") { var bghex = "000000"; var ichex = "9e9e9e" } else if (txt == "white") { var bghex = "ffffff"; var ichex = "eeeeee" } $("#acct_" + key + " .nex").css('color', '#' + ichex); $("#acct_" + key).css('color', '#' + bghex); } } //入力時にハッシュタグと@をサジェスト var timer = null; var input = document.getElementById("url"); var prev_val = input.value; var oldSuggest; var suggest; input.addEventListener("focus", function () { $("#ins-suggest").html(""); window.clearInterval(timer); timer = window.setInterval(function () { var new_val = input.value; if (prev_val != new_val) { if (new_val.length > 3) { var start = "https://instances.social/api/1.0/instances/search?q=" + new_val; fetch(start, { method: 'GET', headers: { 'content-type': 'application/json', 'Authorization': 'Bearer tC8F6xWGWBUwGScyNevYlx62iO6fdQ4oIK0ad68Oo7ZKB8GQdGpjW9TKxBnIh8grAhvd5rw3iyP9JPamoDpeLQdz62EToPJUW99hDx8rfuJfGdjQuimZPTbIOx0woA5M' }, }).then(function (response) { return response.json(); }).catch(function (error) { todo(error); console.error(error); }).then(function (json) { if (!json.error) { var urls = "Suggest:"; Object.keys(json.instances).forEach(function (key) { var url = json.instances[key]; urls = urls + ' ' + escapeHTML(url.name) + ' '; }); $("#ins-suggest").html(urls); } else { console.error(json.error); } }); } oldSuggest = suggest; prev_value = new_val; } }, 1000); }, false); input.addEventListener("blur", function () { window.clearInterval(timer); }, false);