PageSourceSearch

https://9moviestv.cyou/assets/site.js?v=a5

js 9moviestv.cyou collected 2026-10-09 21:49:29 UTC 8,699 bytes, 43 lines download raw bytes

1document.body.dataset.extraRegions='za';
2(() => {
3  'use strict';
4  const base=document.body.dataset.base,brand=document.body.dataset.brand;
5  const key='brand-list:'+brand,regionKey='brand-country:'+brand;
6  const validRegions=new Set(['us','gb','in','ca','au','ph','de','fr','br','mx',...(document.body.dataset.extraRegions||'').split(',').filter(code=>/^[a-z]{2}$/.test(code))]);
7  const read=(k,fallback)=>{try{return JSON.parse(localStorage.getItem(k))??fallback}catch{return fallback}};
8  let saved=read(key,[]);if(!Array.isArray(saved))saved=[];saved=saved.filter(x=>typeof x==='string');
9  let country=read(regionKey,'us');if(!validRegions.has(country))country='us';
10  let timer;
11  function message(text){let node=document.querySelector('.storage-toast');if(!node){node=document.createElement('div');node.className='storage-toast';node.setAttribute('role','status');document.body.append(node)}node.textContent=text;node.hidden=false;clearTimeout(timer);timer=setTimeout(()=>node.hidden=true,3500);document.querySelectorAll('[data-storage-message]').forEach(n=>n.textContent=text)}
12  function write(k,v){try{localStorage.setItem(k,JSON.stringify(v));return true}catch{message('Your browser could not save this change. Check its storage settings.');return false}}
13  const menu=document.querySelector('.menu-toggle'),nav=document.querySelector('#mobile-nav');
14  function closeMenu(){if(!menu||!nav)return;menu.setAttribute('aria-expanded','false');menu.setAttribute('aria-label','Open navigation');nav.hidden=true}
15  menu?.addEventListener('click',()=>{const open=menu.getAttribute('aria-expanded')==='true';menu.setAttribute('aria-expanded',String(!open));menu.setAttribute('aria-label',open?'Open navigation':'Close navigation');nav.hidden=open});
16  document.addEventListener('keydown',e=>{if(e.key==='Escape'&&menu?.getAttribute('aria-expanded')==='true'){closeMenu();menu.focus()}});
17  document.addEventListener('click',e=>{if(!nav?.hidden&&!nav?.contains(e.target)&&!menu?.contains(e.target))closeMenu()});
18  nav?.addEventListener('click',e=>{if(e.target.closest('a'))closeMenu()});
19  window.addEventListener('resize',()=>{if(menu&&getComputedStyle(menu).display==='none')closeMenu()});
20  function syncButtons(){document.querySelectorAll('[data-save]').forEach(b=>{const yes=saved.includes(b.dataset.save);b.setAttribute('aria-pressed',String(yes));b.textContent=yes?'✓ In My List':'+ My List'})}
21  document.addEventListener('click',e=>{const b=e.target.closest('[data-save]');if(!b)return;const id=b.dataset.save,exists=saved.includes(id),next=exists?saved.filter(x=>x!==id):[...saved,id];if(write(key,next)){saved=next;syncButtons();message(exists?'Removed from My List':'Saved to My List');renderList()}});
22  function syncCountry(){document.querySelectorAll('[data-country]').forEach(b=>b.setAttribute('aria-pressed',String(b.dataset.country===country)));document.querySelectorAll('[data-watch-title]').forEach(a=>a.href='https://9moviestv.cyou/home/'+(country==='gb'?'uk':country)+'/search?q='+encodeURIComponent(a.dataset.watchTitle));const notice=document.querySelector('[data-country-notice]'),button=document.querySelector('[data-country="'+country+'"]');if(notice&&button)notice.textContent='Viewing region: '+button.textContent+'.'}
23  document.querySelectorAll('[data-country]').forEach(b=>b.addEventListener('click',()=>{if(write(regionKey,b.dataset.country)){country=b.dataset.country;syncCountry();message('Country preference saved.')}}));
24  syncButtons();syncCountry();
25  let catalog=null;
26  async function getCatalog(){if(catalog)return catalog;const response=await fetch(base+'data/catalog.json');if(!response.ok)throw new Error('Catalog request failed: '+response.status);const data=await response.json();if(!Array.isArray(data.titles))throw new Error('Invalid catalog');return catalog=data.titles}
27  function card(t){const c=document.createElement('article');c.className='card';const a=document.createElement('a');a.className='poster';a.href=t.route;const img=document.createElement('img');img.src=t.poster;img.alt=t.title+' ('+t.year+') poster';img.width=500;img.height=750;img.loading='lazy';a.append(img);if(t.rating>0){const r=document.createElement('span');r.className='rating';r.textContent='★ '+Number(t.rating).toFixed(1);a.append(r)}const h=document.createElement('h3'),link=document.createElement('a');link.href=t.route;link.textContent=t.title;h.append(link);const p=document.createElement('p');p.textContent=t.year+' · '+(t.type==='movie'?'Movie':'TV Series');c.append(a,h,p);return c}
28  function draw(container,items){const grid=document.createElement('div');grid.className='poster-grid';
28items.forEach(t=>grid.append(card(t)));container.replaceChildren(grid)}
29  const list=document.querySelector('[data-watchlist]');
30  async function renderList(){if(!list)return;try{const titles=await getCatalog(),items=titles.filter(t=>saved.includes(t.id));draw(list,items);document.querySelector('[data-list-empty]').hidden=items.length>0}catch{message('Your list could not load. Reload this page to try again.')}}
31  renderList();
32  const form=document.querySelector('[data-filters]');
33  function fold(v){return String(v).normalize('NFKD').replace(/[\u0300-\u036f]/g,'').toLocaleLowerCase().trim()}
34  async function filter(){if(!form)return;try{let items=[...await getCatalog()];const data=new FormData(form),q=fold(data.get('q')||''),type=data.get('type'),genre=data.get('genre'),year=data.get('year'),sort=data.get('sort');items=items.filter(t=>(!q||fold(t.title+' '+t.originalTitle).includes(q))&&(!type||t.type===type)&&(!genre||t.genres.includes(genre))&&(!year||String(t.year)===year));if(sort==='rating')items.sort((a,b)=>b.rating-a.rating);else if(sort==='year')items.sort((a,b)=>String(b.releaseDate).localeCompare(String(a.releaseDate)));else if(sort==='title')items.sort((a,b)=>a.title.localeCompare(b.title));else items.sort((a,b)=>b.popularity-a.popularity);draw(document.querySelector('[data-results]'),items);document.querySelector('[data-empty]').hidden=items.length>0;document.querySelector('[data-result-count]').textContent=items.length+' matching '+(items.length===1?'title':'titles');const params=new URLSearchParams();for(const [k,v] of data){if(v&&!(k==='sort'&&v==='popular'))params.set(k,v)}history.replaceState(null,'',base+'search/'+(params.size?'?'+params:''))}catch{message('Search could not load. Please reload and try again.')}}
35  if(form){const params=new URLSearchParams(location.search);for(const [k,v] of params){const field=form.elements.namedItem(k);if(field&&['q','type','genre','year','sort'].includes(k))field.value=v}form.addEventListener('submit',e=>{e.preventDefault();filter()});form.addEventListener('change',filter);filter()}
36  window.addEventListener('storage',e=>{if(e.key===key){const value=read(key,[]);saved=Array.isArray(value)?value.filter(x=>typeof x==='string'):[];syncButtons();renderList()}if(e.key===regionKey){const value=read(regionKey,'us');country=validRegions.has(value)?value:'us';syncCountry()}});
37  const context=document.modelContext;
38  if(context?.registerTool){const lifecycle=new AbortController();const register=tool=>{try{Promise.resolve(context.registerTool(tool,{signal:lifecycle.signal})).catch(()=>{})}catch{}};
39    register({name:'read_saved_titles',description:'Read the movies and TV shows saved in this browser for '+brand+'.',inputSchema:{type:'object',properties:{},additionalProperties:false},annotations:{readOnlyHint:true,untrustedContentHint:false},async execute(){const titles=await getCatalog();return {brand,titles:titles.filter(t=>saved.includes(t.id)).map(t=>({id:t.id,title:t.title,year:t.year,url:t.route}))}}});
40    register({name:'set_saved_title',description:'Save or remove a catalog title in '+brand+' My List and update the visible saved state.',inputSchema:{type:'object',properties:{id:{type:'string'},saved:{type:'boolean'}},required:['id','saved'],additionalProperties:false},annotations:{readOnlyHint:false,untrustedContentHint:false},async execute(input){if(!input||typeof input.id!=='string'||typeof input.saved!=='boolean'||Object.keys(input).some(k=>!['id','saved'].includes(k)))throw new Error('Expected a title id and a boolean saved value.');const titles=await getCatalog();if(!titles.some(t=>t.id===input.id))throw new Error('Title is not in this catalog.');const next=input.saved?[...new Set([...saved,input.id])]:saved.filter(id=>id!==input.id);if(!write(key,next))throw new Error('Browser storage is unavailable.');saved=next;syncButtons();await renderList();message(input.saved?'Saved to My List':'Removed from My List');return {id:input.id,saved:input.saved}}});
41    window.addEventListener('pagehide',()=>lifecycle.abort(),{once:true});
42  }
43})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.