TheDesk Airi (ver.5)
This commit is contained in:
parent
686d1cd922
commit
2715f602d5
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
*.bat
|
||||
*.zip
|
||||
/TheDesk-*/
|
@ -1,10 +1,11 @@
|
||||
## For Astarte(kirishima.cloud), My Primary Instance
|
||||
|
||||
TheDesk :thedesk: Airi (ver.3)
|
||||
・デフォルトの絵文字に関するバグ修正
|
||||
・改行の描画に関するバグ修正
|
||||
・返信に関するバグ修正
|
||||
・通知を効率化
|
||||
・Spotify NowPlaying機能を追加
|
||||
・脆弱性の修正
|
||||
・絵文字の描画に関する修正
|
||||
【重要】このアップデートは以下の理由で推奨されます。
|
||||
・脆弱性の修正
|
||||
https://thedesk.top
|
||||
:github: https://github.com/cutls/TheDesk #Desk #DeskUpdate
|
||||
|
||||
|
@ -53,7 +53,7 @@ Linuxでご使用の方はチェックを入れて下さい。<br>
|
||||
マストドンバージョン:<span id="ins-ver"></span><br>
|
||||
マストドンアップデート:<span id="ins-sys"></span><br>
|
||||
<script type="text/javascript" src="./js/ui/theme.js"></script>
|
||||
<script type="text/javascript" src="./js/platform/end.js"></script>
|
||||
<script type="text/javascript" src="./js/login/manager.js"></script>
|
||||
<script type="text/javascript" src="./js/login/instance.js"></script>
|
||||
<script type="text/javascript" src="./js/tl/date.js"></script>
|
||||
<script type="text/javascript" src="./js/platform/end.js"></script>
|
||||
<script type="text/javascript" src="./js/tl/date.js"></script>
|
@ -1,5 +1,5 @@
|
||||
/*共通CSS*/
|
||||
html,body{overflow:hidden; user-select: none; cursor:default; font-size:13px;}
|
||||
html,body{overflow:hidden; user-select: none; cursor:default; font-size:13px;height: 100vh;}
|
||||
.btn {
|
||||
margin: 5px;
|
||||
text-transform: none;
|
||||
|
@ -12,6 +12,7 @@
|
||||
}
|
||||
#sidebar{
|
||||
width:75px;
|
||||
min-width:75px;
|
||||
height:100vh;
|
||||
background-color:#e0e0e0;
|
||||
display:flex;
|
||||
@ -83,7 +84,9 @@ iframe {
|
||||
font-size:1.2em;
|
||||
}
|
||||
.emoji-img{
|
||||
width:1.2rem;
|
||||
width: 20px;
|
||||
vertical-align: middle;
|
||||
margin: -3px 0 0;
|
||||
}
|
||||
.tl-box{ height:calc(100% - 40px); overflow-y:scroll; overflow-x:hidden }
|
||||
.additional {
|
||||
|
@ -26,7 +26,7 @@
|
||||
<script type="text/javascript" src="./js/ui/jquery-ui.min.js"></script>
|
||||
<script>
|
||||
//トゥートリンク追加
|
||||
var ver="Airi (ver.4[fixed])";
|
||||
var ver="Airi (ver.5)";
|
||||
//betaを入れるとバージョンチェックしない
|
||||
//var ver="beta";
|
||||
var acct_id=0;
|
||||
@ -35,59 +35,59 @@ var tlid=0;
|
||||
</script>
|
||||
<textarea id="copy" style="top:-100px; position:fixed;"></textarea>
|
||||
<div id="masara">
|
||||
<!--最初にログインする-->ログインしたいインスタンスのアドレス
|
||||
<!--最初にログインする--><span data-trans="want_login">ログインしたいインスタンスのアドレス</span>
|
||||
<br>
|
||||
<input type="text" id="url" style="width:70%" placeholder="mstdn.jp">
|
||||
<div id="ins-suggest">
|
||||
</div>
|
||||
<button class="btn waves-effect" onclick="instance()">Login</button>
|
||||
<br>Linuxでご使用の方はチェックを入れて下さい。
|
||||
<br><span data-trans="linux_ck">Linuxでご使用の方はチェックを入れて下さい。</span>
|
||||
<br>
|
||||
<input type="checkbox" class="filled-in" id="linux" />
|
||||
<label for="linux">コードセットアップ</label>
|
||||
<label for="linux" data-trans="code_setup">コードセットアップ</label>
|
||||
<br>
|
||||
<span style="font-family:Open Sans;">Supports</span>
|
||||
<div id="support">
|
||||
</div>
|
||||
<br>各インスタンスの独自機能もAPIの範囲内で実装させていただきます。お知らせください。
|
||||
<a href="https://kirishima.cloud/@Cutls" target="_blank">Cutls P(@Cutls@kirishima.cloud)</a>まで。
|
||||
<br>ログイン後は設定画面から@Cutls@kirishima.cloudにコンタクトをとることができます。
|
||||
<br><span data-trans="invite_before">各インスタンスの独自機能もAPIの範囲内で実装させていただきます。お知らせください。</span>
|
||||
<a href="https://kirishima.cloud/@Cutls" target="_blank">Cutls P(@Cutls@kirishima.cloud)</a><span data-trans="made">まで。</span>
|
||||
<br><span data-trans="invite_after">ログイン後は設定画面から@Cutls@kirishima.cloudにコンタクトをとることができます。</span>
|
||||
<br>
|
||||
<button class="btn waves-effect indigo" onclick="about()">このソフトについて</button>
|
||||
<button class="btn waves-effect indigo" onclick="about()" data-trans="about">このソフトについて</button>
|
||||
<br>
|
||||
</div>
|
||||
<div id="auth">
|
||||
<!--PINコードで認証-->指定されたコードを貼り付けてください。ログインウィンドウは閉じていただいて構いません。
|
||||
<!--PINコードで認証--><span data-trans="enter_code">指定されたコードを貼り付けてください。ログインウィンドウは閉じていただいて構いません。</span>
|
||||
<br>
|
||||
<input type="text" id="code" placeholder="コードを入力">
|
||||
<button class="btn waves-effect" onclick="code()">認証</button>
|
||||
<input type="text" id="code" placeholder="コードを入力" data-trans-placeholder="code">
|
||||
<button class="btn waves-effect" onclick="code()" data-trans="auth">認証</button>
|
||||
<br>
|
||||
</div>
|
||||
<div id="tl">
|
||||
<!--TL-->
|
||||
<!--ドラッグハンドラ-->
|
||||
<div id="drag">
|
||||
<div id="drag-content">ここにドラッグして添付(ドラッグと同時にアップロードされます)
|
||||
<div id="drag-content" data-trans="drag_here">ここにドラッグして添付(ドラッグと同時にアップロードされます)
|
||||
<br>
|
||||
<button class="btn waves-effect" onclick="closedrop()">閉じる</button>
|
||||
<button class="btn waves-effect" onclick="closedrop()" data-trans="close">閉じる</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--カラム追加-->
|
||||
<div id="add-box" class="hide z-depth-4 notf-box">
|
||||
<div class="input-field">アカウント選択
|
||||
<div class="input-field"><span data-trans="your_acct">アカウント選択</span>
|
||||
<br>
|
||||
<select id="add-acct-sel" class="acct-sel" style="color:black"></select>
|
||||
<label></label>
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<select id="type-sel" style="color:black">
|
||||
<option value="local">ローカル</option>
|
||||
<option value="home">ホーム</option>
|
||||
<option value="pub">連合</option>
|
||||
<option value="mix">統合(ローカルとホーム)</option>
|
||||
<option value="notf">通知</option>
|
||||
<option value="local" data-trans="local">ローカル</option>
|
||||
<option value="home" data-trans="home">ホーム</option>
|
||||
<option value="pub" data-trans="public">連合</option>
|
||||
<option value="mix" data-trans="integrated">統合(ローカルとホーム)</option>
|
||||
<option value="notf" data-trans="notification">通知</option>
|
||||
</select>
|
||||
<label>表示するタイムライン</label>
|
||||
<label data-trans="show_tl">表示するタイムライン</label>
|
||||
</div>
|
||||
<button class="btn waves-effect blue " style="width:calc( 100% - 10px);" onclick="addColumn()">
|
||||
<i class="material-icons left">add</i>追加
|
||||
@ -204,9 +204,9 @@ var tlid=0;
|
||||
</div>
|
||||
<div id="sidebar-btm">
|
||||
<!--最小化-->
|
||||
<div id="menu-btn" onclick="show()">
|
||||
<div id="menu-btn" class="big-menu" onclick="show()">
|
||||
<a class="waves-effect">
|
||||
<i class="large material-icons">mode_edit</i>
|
||||
<i class="material-icons big-icon">mode_edit</i>
|
||||
<br>
|
||||
<span class="side-label">投稿</span>
|
||||
</a>
|
||||
@ -235,6 +235,7 @@ var tlid=0;
|
||||
</div>
|
||||
<span id="radio-sta" class="radio"></span>
|
||||
<div id="radio-view" class="hide radio mize">
|
||||
<a onclick="nowplaying()" class="pointer"><i class="fa fa-spotify"></i>NowPlaying</a>
|
||||
<span class="cbadge pointer waves-effect" onclick="Rplay('https://listen.moe/stream','Listen.moe')" data-name="Listen.moe">Listen.moe</span>
|
||||
<span class="cbadge pointer waves-effect" onclick="Rplay('http://itori.animenfo.com:443/;','AnimeNfo Radio')" data-name="AnimeNfo Radio">AnimeNfo Radio</span>
|
||||
<span class="cbadge pointer waves-effect" onclick="Rplay('http://hyades.shoutca.st:8043/stream','LoFi hip hop Radio')" data-name="LoFi hip hop Radio">LoFi hip hop Radio</span>
|
||||
@ -676,7 +677,7 @@ var tlid=0;
|
||||
<!--左下メッセージ-->
|
||||
<div id="message">
|
||||
</div>
|
||||
<!--Radio-->
|
||||
<!--Radio Happy(Yui) Taku Inoue-->
|
||||
<audio src="" id="radio"></audio>
|
||||
<script type="text/javascript" src="./js/common/about.js"></script>
|
||||
<script type="text/javascript" src="./js/tl/parse.js"></script>
|
||||
@ -699,6 +700,7 @@ var tlid=0;
|
||||
<script type="text/javascript" src="./js/ui/pip.js"></script>
|
||||
<script type="text/javascript" src="./js/ui/radio.js"></script>
|
||||
<script type="text/javascript" src="./js/ui/sort.js"></script>
|
||||
<script type="text/javascript" src="./js/ui/spotify.js"></script>
|
||||
<script type="text/javascript" src="./js/post/post.js"></script>
|
||||
<script type="text/javascript" src="./js/post/reply.js"></script>
|
||||
<script type="text/javascript" src="./js/post/secure.js"></script>
|
||||
|
@ -48,7 +48,7 @@ function defEmoji(target){
|
||||
var after = now.substr(selin, now.length);
|
||||
newt = before+ emoji.emoji + after;
|
||||
}else{
|
||||
newt = now+emoji.emoji;
|
||||
newt = emoji.emoji+now;
|
||||
}
|
||||
console.log(emoji.emoji);
|
||||
$("#textarea").val(newt);
|
||||
|
@ -32,7 +32,7 @@ function load() {
|
||||
var list = key * 1 + 1;
|
||||
templete = '<div class="acct" id="acct_' + key + '">' + list +
|
||||
'.<img src="' + acct.prof + '" width="40" height="40"><div class="text">' +
|
||||
acct.name + ' <span class="gray">' + acct.user + '@' + acct.domain +
|
||||
acct.name + ' <span class="gray">' + escapeHTML(acct.user) + '@' + acct.domain +
|
||||
'</span></div><button class="btn waves-effect disTar" onclick="data(\'' +
|
||||
acct.domain +
|
||||
'\')">インスタンスデータ表示</button><button class="btn waves-effect" onclick="refresh(' +
|
||||
|
200
app/js/tl/mix.js
200
app/js/tl/mix.js
@ -4,10 +4,10 @@ function mixtl(acct_id, tlid) {
|
||||
localStorage.removeItem("morelock")
|
||||
localStorage.setItem("now", type);
|
||||
todo("Integrated TL Loading...(Local)");
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
//まずLocal
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
var at = localStorage.getItem(domain + "_at");
|
||||
//まずLocal
|
||||
var start = "https://" + domain + "/api/v1/timelines/public?local=true";
|
||||
var start = "https://" + domain + "/api/v1/timelines/public?local=true";
|
||||
fetch(start, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@ -19,79 +19,49 @@ function mixtl(acct_id, tlid) {
|
||||
}).catch(function(error) {
|
||||
todo(error);
|
||||
console.error(error);
|
||||
}).then(function(json) {
|
||||
//パースして描画
|
||||
var templete = parse(json, 'mix', acct_id, tlid);
|
||||
$("#timeline_" + tlid).html(templete[0]);
|
||||
}).then(function(jsonL) {
|
||||
var start = "https://" + domain + "/api/v1/timelines/home";
|
||||
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(jsonH) {
|
||||
var homearr=[];
|
||||
var timeline = jsonL.concat(jsonH);
|
||||
timeline.sort(function(a,b){
|
||||
if(date(a.created_at,"unix")>date(b.created_at,"unix")) return -1;
|
||||
if(date(a.created_at,"unix")<date(b.created_at,"unix")) return 1;
|
||||
return 0;
|
||||
});
|
||||
timeline.splice(20);
|
||||
var templete="";
|
||||
Object.keys(timeline).forEach(function(key) {
|
||||
var pkey=key*1+1;
|
||||
if(pkey<20){
|
||||
if(date(timeline[key].created_at,"unix")!=date(timeline[pkey].created_at,"unix")){
|
||||
templete = templete+parse([timeline[key]], '', acct_id, tlid);
|
||||
}
|
||||
}
|
||||
|
||||
jQuery("time.timeago").timeago();
|
||||
$(window).scrollTop(0);
|
||||
var locals = templete[1];
|
||||
var times = templete[2];
|
||||
todo("Integrated TL Loading...(Home)");
|
||||
//Home
|
||||
var start = "https://" + domain + "/api/v1/timelines/home";
|
||||
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(obj) {
|
||||
//ホームのオブジェクトをUnix時間で走査
|
||||
if (!$("[toot-id=" + obj[0].id + "]").length) {
|
||||
$("#timeline_" + tlid + " .cvo").first().before(parse([obj[0]], 'home',
|
||||
acct_id));
|
||||
//delete obj[0];
|
||||
}
|
||||
//Localが遅すぎてHomeの全てより過去の場合
|
||||
var unixL=date(json[0].created_at,"unix");
|
||||
var unixH=date(obj[obj.length-1].created_at,"unix");
|
||||
//console.log(unixH+"vs"+unixL)
|
||||
if(unixH < unixL){
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
var skey = obj.length - key - 1;
|
||||
var toot = obj[skey];
|
||||
var id = toot.id;
|
||||
if ($("#timeline_" + tlid + " [toot-id=" + toot.id + "]").length < 1) {
|
||||
//console.log(toot.id);
|
||||
var tarunix = date(toot.created_at, 'unix');
|
||||
var beforekey2;
|
||||
var key2;
|
||||
//console.log(locals)
|
||||
//ホームのオブジェクトに対してLocalのオブジェクトを時間走査
|
||||
Object.keys(times).forEach(function(key2) {
|
||||
if (times[key2] < tarunix) {
|
||||
var local = json[key2].id;
|
||||
//console.log($.strip_tags(toot.content));
|
||||
html = parse(
|
||||
[toot], 'home', acct_id, tlid);
|
||||
$("#timeline_" + tlid + " [toot-id=" + local + "]").before(html);
|
||||
//console.log("#timeline_" + tlid + " [toot-id=" + local + "]");
|
||||
tarunix = 0;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}else{
|
||||
html = parse(
|
||||
obj, 'home', acct_id, tlid);
|
||||
$("#timeline_" + tlid).html(html);
|
||||
}
|
||||
todc();
|
||||
mixre(acct_id, tlid);
|
||||
});
|
||||
|
||||
$("#timeline_" + tlid).html(templete);
|
||||
mixre(acct_id, tlid);
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
});
|
||||
});
|
||||
todc();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//Streamingに接続
|
||||
function mixre(acct_id, tlid) {
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
@ -181,10 +151,9 @@ function mixmore(tlid) {
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
var at = localStorage.getItem(domain + "_at");
|
||||
var sid = $("#timeline_" + tlid + " .cvo").last().attr("toot-id");
|
||||
var len = $("#timeline_" + tlid + " .cvo").length
|
||||
var start = "https://" + domain +
|
||||
"/api/v1/timelines/public?local=true&max_id=" + sid;
|
||||
console.log(start);
|
||||
|
||||
|
||||
var start = "https://" + domain + "/api/v1/timelines/public?local=true&max_id="+sid;
|
||||
fetch(start, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@ -196,53 +165,46 @@ function mixmore(tlid) {
|
||||
}).catch(function(error) {
|
||||
todo(error);
|
||||
console.error(error);
|
||||
}).then(function(json) {
|
||||
var templete = parse(json, 'mix', acct_id, tlid);
|
||||
$("#timeline_" + tlid).append(templete[0]);
|
||||
var locals = templete[1];
|
||||
todo("Integrated TL MoreLoading...(Home)");
|
||||
console.log(sid);
|
||||
var start = "https://" + domain + "/api/v1/timelines/home?max_id=" + sid;
|
||||
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(obj) {
|
||||
if ($("[toot-id=" + obj[0].id + "]").length < 1) {
|
||||
$("#timeline_" + tlid + " .cvo").eq(len).before(parse([obj[0]], 'home',
|
||||
acct_id)+'<div class="divider"></div>');
|
||||
//delete obj[0];
|
||||
}
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
var skey = obj.length - key - 1;
|
||||
var toot = obj[skey];
|
||||
var id = toot.id;
|
||||
var tarunix = date(toot.created_at, 'unix');
|
||||
var beforekey2;
|
||||
var key2;
|
||||
Object.keys(locals).forEach(function(key2) {
|
||||
if ($("[toot-id=" + toot.id + "]").length <1) {
|
||||
if (key2 > tarunix) {
|
||||
var local = locals[key2];
|
||||
$("#timeline_" + tlid + " [toot-id=" + local + "]").after(parse([toot], 'home',
|
||||
acct_id, tlid));
|
||||
tarunix = 2147483647;
|
||||
}
|
||||
}).then(function(jsonL) {
|
||||
var start = "https://" + domain + "/api/v1/timelines/home?max_id="+sid;
|
||||
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(jsonH) {
|
||||
var homearr=[];
|
||||
var timeline = jsonL.concat(jsonH);
|
||||
timeline.sort(function(a,b){
|
||||
if(date(a.created_at,"unix")>date(b.created_at,"unix")) return -1;
|
||||
if(date(a.created_at,"unix")<date(b.created_at,"unix")) return 1;
|
||||
return 0;
|
||||
});
|
||||
timeline.splice(20);
|
||||
var templete="";
|
||||
Object.keys(timeline).forEach(function(key) {
|
||||
var pkey=key*1+1;
|
||||
if(pkey<20){
|
||||
if(date(timeline[key].created_at,"unix")!=date(timeline[pkey].created_at,"unix")){
|
||||
templete = templete+parse([timeline[key]], '', acct_id, tlid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$("#timeline_" + tlid).append(templete);
|
||||
mixre(acct_id, tlid);
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
todc();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,56 @@ function notf(acct_id, tlid, sys) {
|
||||
console.error('WebSocket Error ' + error);
|
||||
};
|
||||
}
|
||||
//一定のスクロールで発火
|
||||
function notfmore(tlid) {
|
||||
var multi = localStorage.getItem("column");
|
||||
var obj = JSON.parse(multi);
|
||||
var acct_id = obj[tlid].domain;
|
||||
if (!type) {
|
||||
var type = obj[tlid].type;
|
||||
}else{
|
||||
var data;
|
||||
}
|
||||
var sid = $("#timeline_" + tlid + " .cvo").last().attr("toot-id");
|
||||
console.log(sid);
|
||||
if (localStorage.getItem("morelock") != sid) {
|
||||
localStorage.setItem("morelock", sid);
|
||||
localStorage.setItem("now", type);
|
||||
todo("Notfication TL MoreLoading");
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
var at = localStorage.getItem(domain + "_at");
|
||||
var start = "https://" + domain + "/api/v1/notifications"+
|
||||
"max_id=" + sid;
|
||||
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) {
|
||||
var templete="";
|
||||
Object.keys(json).forEach(function(key) {
|
||||
var obj = json[key];
|
||||
if(obj.type!="follow"){
|
||||
templete = templete+parse([obj], '', acct_id, tlid, -1);
|
||||
}else{
|
||||
templete = templete+userparse([obj.account], '', acct_id, tlid, -1);
|
||||
}
|
||||
|
||||
});
|
||||
$("#timeline_" + tlid).append(templete);
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
localStorage.removeItem("morelock")
|
||||
todc();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//通知トグルボタン
|
||||
function notfToggle(acct, tlid) {
|
||||
|
249
app/js/tl/old-mix.js
Normal file
249
app/js/tl/old-mix.js
Normal file
@ -0,0 +1,249 @@
|
||||
//Integrated TL
|
||||
function mixtl(acct_id, tlid) {
|
||||
var type = "mix";
|
||||
localStorage.removeItem("morelock")
|
||||
localStorage.setItem("now", type);
|
||||
todo("Integrated TL Loading...(Local)");
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
var at = localStorage.getItem(domain + "_at");
|
||||
//まずLocal
|
||||
var start = "https://" + domain + "/api/v1/timelines/public?local=true";
|
||||
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) {
|
||||
//パースして描画
|
||||
var templete = parse(json, 'mix', acct_id, tlid);
|
||||
$("#timeline_" + tlid).html(templete[0]);
|
||||
|
||||
jQuery("time.timeago").timeago();
|
||||
$(window).scrollTop(0);
|
||||
var locals = templete[1];
|
||||
var times = templete[2];
|
||||
todo("Integrated TL Loading...(Home)");
|
||||
//Home
|
||||
var start = "https://" + domain + "/api/v1/timelines/home";
|
||||
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(obj) {
|
||||
//ホームのオブジェクトをUnix時間で走査
|
||||
if (!$("[toot-id=" + obj[0].id + "]").length) {
|
||||
$("#timeline_" + tlid + " .cvo").first().before(parse([obj[0]], 'home',
|
||||
acct_id));
|
||||
//delete obj[0];
|
||||
}
|
||||
//Localが遅すぎてHomeの全てより過去の場合
|
||||
var unixL=date(json[0].created_at,"unix");
|
||||
var unixH=date(obj[obj.length-1].created_at,"unix");
|
||||
//console.log(unixH+"vs"+unixL)
|
||||
if(unixH < unixL){
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
var skey = obj.length - key - 1;
|
||||
var toot = obj[key];
|
||||
console.log(toot);
|
||||
var id = toot.id;
|
||||
if ($("#timeline_" + tlid + " [toot-id=" + toot.id + "]").length < 1) {
|
||||
//console.log(toot.id);
|
||||
var tarunix = date(toot.created_at, 'unix');
|
||||
var beforekey2;
|
||||
var key2;
|
||||
//console.log(locals)
|
||||
//ホームのオブジェクトに対してLocalのオブジェクトを時間走査
|
||||
Object.keys(times).forEach(function(key2) {
|
||||
if (times[key2] < tarunix) {
|
||||
var local = json[key2].id;
|
||||
//console.log($.strip_tags(toot.content));
|
||||
html = parse(
|
||||
[toot], 'home', acct_id, tlid);
|
||||
$("#timeline_" + tlid + " [toot-id=" + local + "]").before(html);
|
||||
//console.log("#timeline_" + tlid + " [toot-id=" + local + "]");
|
||||
tarunix = 0;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}else{
|
||||
html = parse(
|
||||
obj, 'home', acct_id, tlid);
|
||||
$("#timeline_" + tlid).html(html);
|
||||
}
|
||||
todc();
|
||||
mixre(acct_id, tlid);
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//Streamingに接続
|
||||
function mixre(acct_id, tlid) {
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
var at = localStorage.getItem(domain + "_at");
|
||||
var type = "mix";
|
||||
localStorage.setItem("now", type);
|
||||
var startHome = "wss://" + domain +
|
||||
"/api/v1/streaming/?stream=user&access_token=" + at;
|
||||
|
||||
var startLocal = "wss://" + domain +
|
||||
"/api/v1/streaming/?stream=public:local&access_token=" + at;
|
||||
var wshid = websocketHome.length;
|
||||
var wslid = websocketLocal.length;
|
||||
websocketHome[wshid] = new WebSocket(startHome);
|
||||
websocketLocal[wslid] = new WebSocket(startLocal);
|
||||
websocketHome[wshid].onopen = function(mess) {
|
||||
console.log("Connect Streaming API(Home)");
|
||||
$("#notice_icon_" + tlid).removeClass("red-text");
|
||||
}
|
||||
websocketLocal[wslid].onopen = function(mess) {
|
||||
console.log("Connect Streaming API(Local)");
|
||||
$("#notice_icon_" + tlid).removeClass("red-text");
|
||||
}
|
||||
websocketLocal[wslid].onmessage = function(mess) {
|
||||
console.log("Receive Streaming API:");
|
||||
|
||||
var obj = JSON.parse(JSON.parse(mess.data).payload);
|
||||
console.log(obj);
|
||||
var type = JSON.parse(mess.data).event;
|
||||
if (type == "delete") {
|
||||
$("[toot-id=" + JSON.parse(mess.data).payload + "]").hide();
|
||||
$("[toot-id=" + JSON.parse(mess.data).payload + "]").remove();
|
||||
} else if (type == "update") {
|
||||
var templete = parse([obj], '', acct_id, tlid);
|
||||
var pool = localStorage.getItem("pool_" + tlid);
|
||||
if (pool) {
|
||||
pool = templete + pool;
|
||||
} else {
|
||||
pool = templete
|
||||
}
|
||||
localStorage.setItem("pool_" + tlid, pool);
|
||||
scrollck();
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
todc();
|
||||
}
|
||||
}
|
||||
websocketHome[wshid].onmessage = function(mess) {
|
||||
console.log("Receive Streaming API:(Home)");
|
||||
|
||||
var obj = JSON.parse(JSON.parse(mess.data).payload);
|
||||
console.log(obj);
|
||||
var type = JSON.parse(mess.data).event;
|
||||
if (type == "delete") {
|
||||
$("[toot-id=" + JSON.parse(mess.data).payload + "]").hide();
|
||||
$("[toot-id=" + JSON.parse(mess.data).payload + "]").remove();
|
||||
} else if (type == "update") {
|
||||
var templete = parse([obj], '', acct_id, tlid);
|
||||
if (obj.visibility != "public" || obj.account.acct != obj.account.username) {
|
||||
var pool = localStorage.getItem("pool_" + tlid);
|
||||
if (pool) {
|
||||
pool = templete + pool;
|
||||
} else {
|
||||
pool = templete
|
||||
}
|
||||
localStorage.setItem("pool_" + tlid, pool);
|
||||
scrollck();
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
}
|
||||
}
|
||||
}
|
||||
websocketLocal[wslid].onerror = function(error) {
|
||||
console.error('WebSocket Error ' + error);
|
||||
};
|
||||
websocketHome[wshid].onerror = function(error) {
|
||||
console.error('WebSocket Error ' + error);
|
||||
};
|
||||
}
|
||||
|
||||
//ある程度のスクロールで発火
|
||||
function mixmore(tlid) {
|
||||
var multi = localStorage.getItem("column");
|
||||
var obj = JSON.parse(multi);
|
||||
var acct_id = obj[tlid].domain;
|
||||
todo("Integrated TL MoreLoading...(Local)");
|
||||
var domain = localStorage.getItem("domain_" + acct_id);
|
||||
var at = localStorage.getItem(domain + "_at");
|
||||
var sid = $("#timeline_" + tlid + " .cvo").last().attr("toot-id");
|
||||
var len = $("#timeline_" + tlid + " .cvo").length
|
||||
var start = "https://" + domain +
|
||||
"/api/v1/timelines/public?local=true&max_id=" + sid;
|
||||
console.log(start);
|
||||
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) {
|
||||
var templete = parse(json, 'mix', acct_id, tlid);
|
||||
$("#timeline_" + tlid).append(templete[0]);
|
||||
var locals = templete[1];
|
||||
todo("Integrated TL MoreLoading...(Home)");
|
||||
console.log(sid);
|
||||
var start = "https://" + domain + "/api/v1/timelines/home?max_id=" + sid;
|
||||
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(obj) {
|
||||
if ($("[toot-id=" + obj[0].id + "]").length < 1) {
|
||||
$("#timeline_" + tlid + " .cvo").eq(len).before(parse([obj[0]], 'home',
|
||||
acct_id)+'<div class="divider"></div>');
|
||||
//delete obj[0];
|
||||
}
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
var skey = obj.length - key - 1;
|
||||
var toot = obj[skey];
|
||||
var id = toot.id;
|
||||
var tarunix = date(toot.created_at, 'unix');
|
||||
var beforekey2;
|
||||
var key2;
|
||||
Object.keys(locals).forEach(function(key2) {
|
||||
if ($("[toot-id=" + toot.id + "]").length <1) {
|
||||
if (key2 > tarunix) {
|
||||
var local = locals[key2];
|
||||
$("#timeline_" + tlid + " [toot-id=" + local + "]").after(parse([toot], 'home',
|
||||
acct_id, tlid));
|
||||
tarunix = 2147483647;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
todc();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
@ -130,12 +130,6 @@ function parse(obj, mix, acct_id, tlid, popup) {
|
||||
}
|
||||
}
|
||||
var id = toot.id;
|
||||
//Integratedである場合はUnix時間をキーに配列を生成しておく
|
||||
if (mix == "mix") {
|
||||
local[date(obj[key].created_at, 'unix')] = toot.id;
|
||||
times.push(date(obj[key].created_at, 'unix'));
|
||||
var divider = '<div class="divider"></div>';
|
||||
}
|
||||
if (mix == "home") {
|
||||
var home = "Home TLより"
|
||||
var divider = '<div class="divider"></div>';
|
||||
@ -169,7 +163,7 @@ function parse(obj, mix, acct_id, tlid, popup) {
|
||||
}
|
||||
if (toot.spoiler_text && cw) {
|
||||
var content = toot.content;
|
||||
var spoil = toot.spoiler_text;
|
||||
var spoil = escapeHTML(toot.spoiler_text);
|
||||
var spoiler = "cw cw_hide_" + toot.id;
|
||||
var api_spoil = "gray";
|
||||
var spoiler_show = '<a href="#" onclick="cw_show(\'' + toot.id +
|
||||
@ -187,7 +181,7 @@ function parse(obj, mix, acct_id, tlid, popup) {
|
||||
'\')" class="nex parsed">続き…</a><br>';
|
||||
} else {
|
||||
var content = toot.content;
|
||||
var spoil = toot.spoiler_text;
|
||||
var spoil = escapeHTML(toot.spoiler_text);
|
||||
var spoiler = "";
|
||||
var spoiler_show = "";
|
||||
}
|
||||
@ -218,7 +212,7 @@ function parse(obj, mix, acct_id, tlid, popup) {
|
||||
'" class="emoji-img">';
|
||||
var regExp = new RegExp(":" + shortcode + ":", "g");
|
||||
content = content.replace(regExp, emoji_url);
|
||||
spoil = toot.spoiler_text.replace(regExp, emoji_url);
|
||||
spoil = spoil.replace(regExp, emoji_url);
|
||||
});
|
||||
}
|
||||
var mediack = toot.media_attachments[0];
|
||||
@ -439,7 +433,7 @@ function userparse(obj, auth, acct_id, tlid, popup) {
|
||||
}
|
||||
var memory = localStorage.getItem("notice-mem");
|
||||
if (popup >= 0 && obj.length < 5 && noticetext != memory) {
|
||||
Materialize.toast(toot.display_name+"にフォローされました", popup * 1000);
|
||||
Materialize.toast(escapeHTML(toot.display_name)+"にフォローされました", popup * 1000);
|
||||
$(".notf-icon_" + tlid).addClass("red-text");
|
||||
localStorage.setItem("notice-mem", noticetext);
|
||||
noticetext = "";
|
||||
@ -453,7 +447,7 @@ function userparse(obj, auth, acct_id, tlid, popup) {
|
||||
'<img src="' + toot.avatar + '" width="40" class="prof-img" user="' + toot
|
||||
.acct + '"></a></div>' +
|
||||
'<div style="flex-grow:3; overflow: hidden;white-space: nowrap;text-overflow: ellipsis;user-select:auto; cursor:text;"><big>' +
|
||||
toot.display_name + '</big></div>' +
|
||||
escapeHTML(toot.display_name) + '</big></div>' +
|
||||
'<div class="sml gray" style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;user-select:auto; cursor:text;"> @' +
|
||||
toot.acct + locked + '</div>' +
|
||||
'</div>' + auth +
|
||||
|
@ -182,6 +182,9 @@ function moreload(type, tlid) {
|
||||
if (type == "mix") {
|
||||
mixmore(tlid);
|
||||
return;
|
||||
}else if (type == "notf") {
|
||||
notfmore(tlid);
|
||||
return;
|
||||
}
|
||||
localStorage.setItem("now", type);
|
||||
todo(cap(type) + " TL MoreLoading");
|
||||
@ -205,6 +208,7 @@ function moreload(type, tlid) {
|
||||
$("#timeline_" + tlid).append(templete);
|
||||
additional(acct_id, tlid);
|
||||
jQuery("time.timeago").timeago();
|
||||
localStorage.removeItem("morelock")
|
||||
todc();
|
||||
});
|
||||
}
|
||||
|
@ -47,12 +47,14 @@ function xpand() {
|
||||
if ($("#sidebar").hasClass("xed")) {
|
||||
$(".side-label").show();
|
||||
$("#sidebar").css('width', '75px');
|
||||
$("#sidebar").css('min-width', '75px');
|
||||
$("#sidebar .big-menu i").addClass('big-icon');
|
||||
$("#sidebar").removeClass("xed");
|
||||
$("#x-btn").text("keyboard_arrow_right");
|
||||
localStorage.removeItem("xed");
|
||||
} else {
|
||||
$("#sidebar").css('width', '24px');
|
||||
$("#sidebar").css('min-width', '24px');
|
||||
$("#sidebar").addClass("xed");
|
||||
$("#sidebar .big-menu i").removeClass('big-icon');
|
||||
$(".side-label").hide();
|
||||
|
@ -25,7 +25,7 @@ function scrollck() {
|
||||
}
|
||||
}
|
||||
//続きを読むトリガー
|
||||
var scrt = $(this).find(".tl").height() - 1500;
|
||||
var scrt = $(this).find(".tl").height() - $(window).height();
|
||||
var scr = $(this).scrollTop();
|
||||
if (scr > scrt) {
|
||||
moreload('', tlid);
|
||||
|
@ -211,6 +211,7 @@ load();
|
||||
climute();
|
||||
wordmute();
|
||||
wordemp();
|
||||
checkSpotify();
|
||||
function climute(){
|
||||
//クライアントミュート
|
||||
var cli = localStorage.getItem("client_mute");
|
||||
|
76
app/js/ui/spotify.js
Normal file
76
app/js/ui/spotify.js
Normal file
@ -0,0 +1,76 @@
|
||||
function spotifyConnect(){
|
||||
var auth = "https://accounts.spotify.com/authorize?client_id=0f18e54abe0b4aedb4591e353d3aff69&redirect_uri=https://thedesk.top/spotify-connect&response_type=code&scope=user-read-currently-playing";
|
||||
const {
|
||||
shell
|
||||
} = require('electron');
|
||||
|
||||
shell.openExternal(auth);
|
||||
var electron = require("electron");
|
||||
var ipc = electron.ipcRenderer;
|
||||
ipc.send('quit', 'go');
|
||||
|
||||
}
|
||||
function spotifyDisconnect(){
|
||||
localStorage.removeItem("spotify");
|
||||
localStorage.removeItem("spotify-refresh");
|
||||
checkSpotify();
|
||||
}
|
||||
function checkSpotify(){
|
||||
if(localStorage.getItem("spotify")){
|
||||
$("#spotify-enable").addClass("disabled");
|
||||
$("#spotify-disable").removeClass("disabled");
|
||||
}else{
|
||||
$("#spotify-enable").removeClass("disabled");
|
||||
$("#spotify-disable").addClass("disabled");
|
||||
}
|
||||
console.log(localStorage.getItem("spotify-refresh"));
|
||||
}
|
||||
function nowplaying(){
|
||||
var start = "https://thedesk.top/now-playing?at="+localStorage.getItem("spotify")+"&rt="+localStorage.getItem("spotify-refresh");
|
||||
var at = localStorage.getItem("spotify");
|
||||
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) {
|
||||
console.log(json);
|
||||
var item=json.item;
|
||||
var content=localStorage.getItem("np-temp");
|
||||
if(!content){
|
||||
var content="#NowPlaying {song} / {album} / {artist}\n{url} #Spotify-with-TheDesk";
|
||||
}
|
||||
var regExp = new RegExp("{song}", "g");
|
||||
content = content.replace(regExp, item.name);
|
||||
var regExp = new RegExp("{album}", "g");
|
||||
content = content.replace(regExp, item.album.name);
|
||||
var regExp = new RegExp("{artist}", "g");
|
||||
content = content.replace(regExp, item.artists[0].name);
|
||||
var regExp = new RegExp("{url}", "g");
|
||||
content = content.replace(regExp, item.href);
|
||||
$("#textarea").val(content);
|
||||
});
|
||||
}
|
||||
function spotifySave(){
|
||||
var temp=$("#np-temp").val();
|
||||
localStorage.setItem("np-temp", temp);
|
||||
Materialize.toast("NowPlaying文章を更新しました。", 3000);
|
||||
}
|
||||
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=="spotify"){
|
||||
var coder=codex.split(":");
|
||||
localStorage.setItem("spotify", coder[0]);
|
||||
localStorage.setItem("spotify-refresh", coder[1]);
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
}
|
21
app/main.js
21
app/main.js
@ -123,6 +123,16 @@ ipc.on('download-btn', (e, args) => {
|
||||
var zip="TheDesk-win32-ia32.zip";
|
||||
}
|
||||
}else if(platform=="linux"){
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Linux Supporting System',
|
||||
message: "thedesk.topをブラウザで開きます。",
|
||||
buttons: ['OK']
|
||||
}
|
||||
dialog.showMessageBox(options, function(index) {
|
||||
shell.openExternal("https://thedesk.top");
|
||||
})
|
||||
return;
|
||||
if(bit=="x64"){
|
||||
var zip="TheDesk-linux-x64.zip";
|
||||
}else if(bit=="ia32"){
|
||||
@ -226,17 +236,6 @@ ipc.on('about', (e, args) => {
|
||||
"resizable": false });
|
||||
window.loadURL('file://' + __dirname + '/about.html?ver='+ver);
|
||||
return "true"
|
||||
/*
|
||||
openAboutWindow({
|
||||
icon_path: join(__dirname, 'desk.png'),
|
||||
copyright: 'Copyright (c) TheDesk on Mastodon 2018 & Cutls.com 2015 All Rights Reserved. CDN provided by AWS CloudFront.',
|
||||
license: 'This work is licensed under TheDesk LICENSE. See also GitHub.',
|
||||
description: 'ここに表示されているバージョンは内部バージョンで、一般的に使われている愛称とは異なります。',
|
||||
bug_report_url: 'https://cutls.com/report',
|
||||
css_path: join(__dirname, './css/about.css'),
|
||||
adjust_window_size: true
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
ipc.on('column-del', (e, args) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TheDesk",
|
||||
"version": "13.4.1",
|
||||
"version": "13.5.0",
|
||||
"description": "TheDesk on Mastodonはシンプルと多機能を両立したデスクトップ向けクライアントです",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
@ -168,6 +168,22 @@
|
||||
<span class="emphasized"> 強調色(テーマによって異なります。) </span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">
|
||||
<i class="fa fa-spotify"></i>SpotifyとNowPlayingの設定
|
||||
</div>
|
||||
<div class="collapsible-body">
|
||||
<i class="material-icons nex" title="Radio(Select/Pause)">play_circle_outline</i>ボタンで表示されるメニューから簡単にNowPlayingができます。<br>
|
||||
Windowsのみの対応です。APIの性質上,thedesk.topへアクセスします。<br>
|
||||
<a onclick="spotifyConnect()" class="btn waves-effect nex" style="width:100%; max-width:200px; background-color:#1ed760;" id="spotify-enable"><i class="fa fa-spotify left"></i>接続</a>
|
||||
<a onclick="spotifyDisconnect()" class="btn waves-effect nex disabled" style="width:100%; max-width:200px; background-color:#1ed760;" id="spotify-disable"><i class="fa fa-spotify left"></i>切断</a>
|
||||
<br>トゥートテンプレート<br>
|
||||
<textarea id="np-temp" class="materialize-textarea" data-length="500">#NowPlaying {song} / {album} / {artist}
|
||||
{url} #Spotify-with-TheDesk</textarea><br>
|
||||
テンプレート:{song}:曲名/{album}:アルバム名/{artist}:アーティスト名/{url}:各曲のSpotifyのURL<br>
|
||||
<button onclick="spotifySave()" class="btn waves-effect" style="width:100px;">設定</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
<a href="index.html" class="btn waves-effect orange nex" style="width:100%; max-width:200px;"><i class="material-icons left">undo</i>戻る</a>
|
||||
@ -223,6 +239,7 @@
|
||||
<script type="text/javascript" src="./js/common/about.js"></script>
|
||||
<script type="text/javascript" src="./js/platform/end.js"></script>
|
||||
<script type="text/javascript" src="./js/login/logout.js"></script>
|
||||
<script type="text/javascript" src="./js/ui/spotify.js"></script>
|
||||
<script type="text/javascript" src="./js/ui/settings.js"></script>
|
||||
<script type="text/javascript" src="./js/ui/theme.js"></script>
|
||||
<script type="text/javascript" src="./js/tl/date.js"></script>
|
2
ver.json
2
ver.json
@ -1 +1 @@
|
||||
{"warn":"これはGCPにアップして下さい!!","warn2":"これはGCPにアップして下さい!!","warn3":"これはGCPにアップして下さい!!","desk":"Airi (ver.4[fixed])","date":"2018-03-14","detail":"内部V:13.4.0|いくつかのバグを修正。機能改修。"}
|
||||
{"warn":"これはGCPにアップして下さい!!","warn2":"これはGCPにアップして下さい!!","warn3":"これはGCPにアップして下さい!!","desk":"Airi (ver.5)","date":"2018-03-15","detail":"内部V:13.5.0|バグ修正。Spotify Now Playing対応"}
|
Loading…
Reference in New Issue
Block a user