エピソード系チェック
2022-12-03
アイドルエピソード系
作業用Discordサーバー用として掲載しており、加筆修正の可能性があります
エピソード一覧表
複数Pさんにご協力いただいて組んだものになります。
恐らくそのままブラウザで開くと文字化けするので、
右クリックから「名前を付けてリンク先を保存」などしてDLを挟んでください
✨ idol_episode_list.txt ✨
上記テキストは Excel , Googleスプレッドシート に直接貼り付けると管理が楽なのでドチャクソお勧めです。
( Googleドライブ上に保存されます )
上記表を自作の雑なツールで変換した .json
で良ければ、以下もどうぞ。
( ※中身ちゃんと精査していない)
🙄 idol_episode_list.json 🙄
[Task-1] アイドルエピソード一覧の確認
後述のスクリプト [Script-A] を実行し、ファイルを出力。
中身を確認後、不明扱いのエピソードIDが記載(=判明)されていればそれを教えて頂きたい
...というものです。
※ 12/6 02:30 頃更新
残り 367
1点...だが、運営的欠番の可能性が高い
解放しているアイドルエピソード一覧の確認用スクリプト
- 実行場所
多分どこでもOK - 機能・効果など
バックグラウンドでアイドルギャラリーにアクセスし、
そのデレドルのエピソード情報(割り振られているIDや、解放の有無)を回収します
所要時間 2分程? ( DevTools 眺めていれば、巡回ログが都度出るのでわかりやすいハズ )
全工程終了のち、情報をまとめたテキストが 計2つ DLされます
( + オマケで親愛埋め状況のカウントテキストが書出 )
Tab
記号で整形しているので、Excelや Googleスプレッドシート 等に貼り付け・管理できるようにしています。
✨ 貼り付け→エピソードIDでソートすると楽 - 注意点
途中でページを移動したり閉じてしまうと処理が破棄されます
その場合は最初からやり直してください - 末尾番号のみ
末尾に番号のみで表記された各行は
髭同様「そのアカウントで存在が取得できなかったエピソード番号」です。
[Script-A] アイドルギャラリーページ内からエピソード一覧取得 / 巡回一括DL版
※ マウスオーバーで、コード右端上に Copy ボタンが表示されます
(async()=>{
const _galleryList = await fetch("https://mkt.packetroom.net/script/idol_gallery_list.json",{mode:"cors"}).then(_res=>_res.json()).catch(_err=>{ console.warn(`${_err} アクセス失敗`);});
const _dlTargetDefObj = [];
_galleryList.forEach(_e=>{
const _nameKey = Object.keys(_e)[0];
const _hash = _e[_nameKey];
const _url = `https://sp.pf.mbga.jp/12008305/?guid=ON&url=http://mobamas.net/idolmaster/idol_gallery/idol_detail/${_hash}`;
const _dlFileName = `${_nameKey}`;
console.info(_nameKey , _hash);
_dlTargetDefObj.push( { "idol_name" : _nameKey , "url" : _url , "optionExt" : ".json"} );
});
const _resultList = [];
const _loveResultList = [];
const _existStoryObj = {};
console.info("================== 巡回アクセス & DL処理を開始します ==================");
function _fileDl(_dlInfo , _index) {
return new Promise((resolve,reject) => {
const _idolName = _dlInfo["idol_name"];
const _url = _dlInfo["url"];
setTimeout(async () => {
const _restext = await fetch(_url,{ method: "GET"})
.then(_res=>{
if(!_res.ok){
throw new Error(_res.statusText);
}else{
return _res.text();
}
})
.catch(_err=>{
console.warn(`${_idolName} アクセス失敗`);
});
let _sucess = false;
// === 何らかのレス 取得成功と判断
if(_restext){
const _dPsr = new DOMParser();
const _doc = _dPsr.parseFromString(_restext , "text/html");
const _scr = [..._doc.scripts].find(_e=> _e.textContent.length>6000);
let _idols,_strys;
try{
const _m = _scr.textContent.match(/idol\.detail_list = (\[.*);\nidol\.idol_story_list = (\[.*\]);\nidol\.images/);
_idols = JSON.parse(_m[1]);
_strys = JSON.parse(_m[2]);
_sucess = true;
}catch(_err){ console.error(_err); }
if(!_sucess){ console.error("パース関連の予期せぬ例外:失敗,中断"); reject(); return; }
let _lMax = 0;
let _cardCount = _idols.length;
const _cID = _idols[0].profile.card_id; // ソートカテゴリ用
const _name = _idolName;//_idols[0].profile.card_name;
_idols.forEach(_i=>{ (_i.is_max_love?(_lMax++):0); });
_strys.forEach(_s=>{
let _arr = [];
const _id = _s.story_id;
// 最大エピソード数3前提
let _epiPartIdArr = ["","",""];
let _epiOpenFlgArr = ["","",""];
// open_flag のキー名(または配列index)と、_s.flash_path のキー名は同じ長さ且つ合致した前提とする
let _tempIndex = 0;
for(let _key in _s.open_flag){
const _flashUrl = decodeURIComponent(_s.flash_path[_key]);
const _epiPartId = _flashUrl.split("/movie_play/").pop().split("/")[1];
_epiPartIdArr[_tempIndex] = _epiPartId;
_epiOpenFlgArr[_tempIndex] = _s.open_flag[_key];
_tempIndex++;
}
// エピID,サブパートIDx3枠,タイトル,アイドル名,ソート用アイドルID,エピ開放記録x3枠
_arr = [ _id , ..._epiPartIdArr , _s.story_title , _name , _cID , ..._epiOpenFlgArr ];
_existStoryObj[_id] = true;
_tempMinId = _id;
_resultList.push(_arr);
})
console.info(`${_name} 親愛MAX数 ${_lMax} / ${_cardCount}`);
_loveResultList.push( [ _name , _lMax , _cardCount , _cID , (_lMax==_cardCount?"◎":"")] );
}
if(_sucess != true){
console.warn(_idolName , "失敗判定");
_resultList.push("failed");
}
resolve();
}, 100); // DL間隔ミリ秒。あまり縮めないほうが良い
});
}
// 実処理開始
(async () => {
await _dlTargetDefObj.reduce((promise, _dlInfo , _currentIndex) => {
return promise.then(async () => {
await _fileDl(_dlInfo , _currentIndex);
});
}, Promise.resolve());
console.info("=== ギャラリーページへのアタッチ終了 ====");
const _missingList = []; // 欠番処理
{
const _objLen = Object.keys(_existStoryObj).length;
let _lastNumKey = Object.keys(_existStoryObj)[_objLen-1];
for(let _n=1; _lastNumKey>=_n; _n++){ if(!(_n in _existStoryObj)){ _missingList.push(_n) } };
}
{
let _outStr = `アイドルストーリ解放状況 ( 結果 : およそ ${_resultList.length} 行分 )\n`
+ "※ 実装されているが、ギャラリー上に表示されないストーリーが(例え親愛埋めMAXでも)あり得るので注意\n"
+ "未参加イベント?や(上位系)特別編等がこれに相当する模様?\n"
+ "(末行の)空白行は巡回で確認できなかったエピソードです\n"
+ "タブで整形されているので、Excel,スプレッドシート等にそのまま貼り付け・ソートなどが可能です\n"
+ "p1~p3はエピソードID内の小分けパートです。前後編ならp1,p2で、中編あればp3まで\n"
+ "op1~はopen(開放)を示し、p1~同様その対応エピソードパートの開放を示します(1:開放,0:未開放)\n\n\n\n"
+ "episode_id\tp1\tp2\tp3\tstory_name\tidol_name\tprovisional_id\top1\top2\top3\n";
_resultList.forEach((_e)=>{ _outStr += ( _e.join("\t") ) + "\n"; });
_missingList.forEach((_e)=>{ _outStr += ( `${_e}` ) + "\n"; });
const _dlUrl = URL.createObjectURL( new Blob([_outStr+"\n\n"] , {type: "text/plain"}) );
const _a = document.createElement('a');
_a.href = _dlUrl;
_a.download = `_エピソード一覧.txt`;
document.body.appendChild(_a); _a.click();
console.info(`${_a.download} をDLしました`);
document.body.removeChild(_a);
URL.revokeObjectURL(_dlUrl);
}
{
let _outStr = `親愛度MAX数 ( 結果 : およそ ${_loveResultList.length} 行分 )\n`
+ "タブで整形されているので、Excel,スプレッドシート等にそのまま貼り付け・ソートなどが可能です\n\n\n\n"
+ "idol_name\tnow\tmax\tprovisional_id\tfull\n";
_loveResultList.forEach((_e)=>{ _outStr += ( _e.join("\t") ) + "\n"; });
const _dlUrl = URL.createObjectURL( new Blob([_outStr+"\n\n"] , {type: "text/plain"}) );
const _a = document.createElement('a');
_a.href = _dlUrl;
_a.download = `_親愛埋め数リスト.txt`;
document.body.appendChild(_a); _a.click();
console.info(`${_a.download} をDLしました`);
document.body.removeChild(_a);
URL.revokeObjectURL(_dlUrl);
}
})();
})();