Skip to content

Instantly share code, notes, and snippets.

@ooharak
Last active September 20, 2026 02:26
Show Gist options
  • Select an option

  • Save ooharak/c0f9ec4b847ab09e9a8b75c400054f04 to your computer and use it in GitHub Desktop.

Select an option

Save ooharak/c0f9ec4b847ab09e9a8b75c400054f04 to your computer and use it in GitHub Desktop.
ももクロ月間スケジュールを月末まで一括表示に変えるブックマークレット(月に移動してからクリック)
javascript:(async()=>{const ID='mcz-table';if(document.getElementById(ID))return;if(!/^(www\.)?momoclo\.net$/.test(location.hostname)){alert('ももクロ公式サイトで実行してください');return;}const host=document.createElement('div');host.id=ID;host.style.cssText='all:initial!important;position:fixed!important;inset:0!important;z-index:2147483647!important;background:white!important;';const root=host.attachShadow({mode:'open'});root.innerHTML='<style>*{box-sizing:border-box;text-align:left!important;letter-spacing:normal}.panel{height:100dvh;display:flex;flex-direction:column;background:white;color:#222;font:12px/1.3 sans-serif}.bar{display:flex;align-items:center;gap:10px;padding:7px 10px;border-bottom:1px solid #767676}.bar strong{font-size:14px}.bar button{margin-left:auto;padding:3px 10px;cursor:pointer;font:12px sans-serif}#status{padding:5px 10px;font-size:11px;white-space:pre-wrap}.scroll{overflow:auto;flex:1;min-height:0;padding:0 8px 12px}table{width:100%;min-width:760px;border-collapse:collapse;table-layout:fixed;font:12px/1.3 sans-serif}th,td{padding:4px 6px;border:1px solid #767676;vertical-align:top;font-weight:normal;overflow-wrap:anywhere;color:#222}thead th{position:sticky;top:0;background:#eee;font-weight:bold;z-index:1}.date{white-space:nowrap}.cat{font-size:11px;font-weight:bold}.note{font-size:11px}.month td{background:#eee;font-weight:bold}a{color:#174f78;text-decoration:underline;margin-left:5px}</style><div class="panel"><div class="bar"><strong>ももクロ・スケジュール一覧</strong><button type="button">閉じる</button></div><div id="status" role="status"></div><div class="scroll"><table><colgroup><col style="width:88px"><col style="width:82px"><col style="width:43%"><col style="width:150px"><col></colgroup><thead><tr><th>月/日(曜日)</th><th>区分</th><th>タイトル</th><th>時間など</th><th>備考</th></tr></thead><tbody></tbody></table></div></div>';document.documentElement.appendChild(host);const ac=new AbortController();root.querySelector('button').onclick=()=>{ac.abort();host.remove();};const status=root.querySelector('#status'),body=root.querySelector('tbody');const parts=new Intl.DateTimeFormat('en-US',{timeZone:'Asia/Tokyo',year:'numeric',month:'numeric'}).formatToParts(new Date());let y=+parts.find(p=>p.type==='year').value,m=+parts.find(p=>p.type==='month').value,months=0,total=0;const clean=s=>(s||'').replace(/\s+/g,' ').trim();const text=(e,s)=>clean(e.querySelector(s)?.textContent);const cell=(row,value,cls)=>{const td=document.createElement('td');td.className=cls||'';td.textContent=value;row.appendChild(td);return td;};const palette={TV:'#E8F1FA',RADIO:'#FFF2CC',LIVE:'#E0F2EC',EVENT:'#FBE8D5',STREAMING:'#EEE8F7',MAGAZINE:'#F7E8EF',BOOK:'#F7E8EF',WEB:'#E7F2F5',MUSIC:'#E0F2EC',MOVIE:'#EEE8F7',TICKET:'#FFF2CC'};try{while(host.isConnected){const label=y+'年'+m+'月';status.textContent=label+'を取得中… '+months+'か月・'+total+'件取得済み';const url=new URL('/schedule',location.origin);url.searchParams.set('target_year',y);url.searchParams.set('target_month',String(m).padStart(2,'0'));const timer=setTimeout(()=>ac.abort(),30000);let doc;try{const res=await fetch(url,{signal:ac.signal,credentials:'omit'});if(!res.ok)throw Error('HTTP '+res.status);doc=new DOMParser().parseFromString(await res.text(),'text/html');}finally{clearTimeout(timer);}const rows=Array.from(doc.querySelectorAll('.schedule_list_container')).filter(e=>e.querySelector('.schedule_list_title'));if(!rows.length){if(!/お探しの記事が見つかりませんでした/.test(doc.body.textContent))throw Error(label+'の予定を確認できませんでした');status.textContent=months?'取得完了:'+months+'か月・'+total+'件('+label+'が未登録のため終了)':label+'は未登録です';break;}const heading=document.createElement('tr');heading.className='month';cell(heading,label+' / '+rows.length+'件').colSpan=5;body.appendChild(heading);for(const e of rows){const row=document.createElement('tr');const day=parseInt(text(e,'.schedule_list_day'),10);const week=Number.isFinite(day)?'日月火水木金土'[new Date(y,m-1,day).getDay()]:text(e,'.schedule_list_week');cell(row,m+'/'+(Number.isFinite(day)?day:'?')+'('+week+')','date');const category=text(e,'.schedule_list_genre_box');cell(row,category,'cat');cell(row,text(e,'.schedule_list_title'));const p=e.querySelector('.schedule_list_text');let full='';if(p){const copy=p.cloneNode(true);copy.querySelectorAll('br').forEach(b=>b.replaceWith(' '));full=clean(copy.textContent);}let rest=full.replace(/(?:\d{4}\s*[\//年]\s*)?\d{1,2}\s*[\//月]\s*\d{1,2}\s*日?\s*[((][日月火水木金土](?:曜日|曜)?[))]/g,'').trim();const pattern=/(?:(?:開場|開演|開始|放送|配信|受付|集合)\s*[::]?\s*)?(?:午前\s*|午後\s*)?[0-2]?\d[::][0-5]\d(?:\s*[~〜~-–—-]\s*(?:[0-2]?\d[::][0-5]\d)?)?(?:\s*(?:配信開始|放送開始|開場|開演|予定|頃|ごろ))?/g;cell(row,(rest.match(pattern)||[]).join(' / ')||'—');rest=clean(rest.replace(pattern,' ').replace(/^[\s、,\//::・]+|[\s、,\//::・]+$/g,''));const note=cell(row,rest.length>40?rest.slice(0,40)+'…':rest,'note');note.title=full;let n=0;for(const a of e.querySelectorAll('.schedule_list_link a[href]')){const u=new URL(a.getAttribute('href'),url);if(!/^https?:$/.test(u.protocol))continue;const link=document.createElement('a');link.href=u.href;link.target='_blank';link.rel='noopener noreferrer';n+=1;link.textContent='詳細'+(n>1?n:'');link.title=clean(a.textContent)||u.href;note.appendChild(link);}const bg=palette[category.toUpperCase()]||'#F0F0F0';for(const td of row.cells){td.style.backgroundColor=bg;}body.appendChild(row);}months+=1;total+=rows.length;m+=1;if(m>12){m=1;y+=1;}}}catch(e){if(host.isConnected){status.textContent='取得中断:'+months+'か月・'+total+'件まで表示。全件取得は未完了です。\n'+(e.name==='AbortError'?'通信がタイムアウトしました。':e.message);}}})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment