Popmundo envanter paneli — çok dilli arayüz, otomatik tarama, arama, fiyat takibi ve CSV
// ==UserScript==
// @name 📦 Depot
// @name:en 📦 Depot
// @name:pt-BR 📦 Depot
// @namespace popmundo.inventory
// @version 2.1
// @description Popmundo envanter paneli — çok dilli arayüz, otomatik tarama, arama, fiyat takibi ve CSV
// @description:en Popmundo inventory panel — multilingual UI, auto-scan, search, price tracking & CSV export
// @description:pt-BR Painel de inventário Popmundo — multilíngue, varredura automática, busca, preços e CSV
// @author luke-james-gibson
// @license MIT
// @id dpv9q3
// @supportURL https://greasyfork.org/tr/scripts/568770-popmundo-envanter
// @match https://*.popmundo.com/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant unsafeWindow
// ==/UserScript==
(function () {
'use strict';
// ─── POPCONTROL DISABLE CHECK ────────────────────────────────────────────────
try { const _ppc = JSON.parse(localStorage.getItem('ppc_enabled')||'{}'); if (_ppc['depot'] === false) return; } catch {}
// Language
const LANG = (() => { try { const c = document.cookie.match(/ppm_lang=([^;]+)/); return c ? c[1] : 'TR'; } catch { return 'TR'; } })();
const _D = (tr, en, pt) => ({ TR: tr, EN: en, 'PT-BR': pt }[LANG] || tr);
const S = {
// Scan modal
scanTitle: _D('🔄 Otomatik Tarama', '🔄 Auto Scan', '🔄 Varredura Automática'),
scanPersonal: _D('👤 Kişisel Eşyalar', '👤 Personal Items', '👤 Itens Pessoais'),
scanVehicles: _D('🚗 Kişisel Araçlar', '🚗 Personal Vehicles', '🚗 Veículos Pessoais'),
scanHousing: _D('🏠 Evler', '🏠 Housing', '🏠 Moradias'),
scanArtist: _D('🎵 Sanatçı / Turne Aracı', '🎵 Artist / Tour Vehicle', '🎵 Artista / Veículo de Turnê'),
scanWarn: _D('⚠️ Tarama sırasında sekmeler otomatik değişir.', '⚠️ Tabs will change automatically during scan.', '⚠️ As abas mudarão automaticamente durante a varredura.'),
scanCancel: _D('İptal', 'Cancel', 'Cancelar'),
scanStart: _D('▶ Taramayı Başlat', '▶ Start Scan', '▶ Iniciar Varredura'),
scanSelectOne: _D('En az bir kategori seçin.', 'Select at least one category.', 'Selecione pelo menos uma categoria.'),
// Scan report
scanDone: _D('✅ Tarama Tamamlandı', '✅ Scan Complete', '✅ Varredura Concluída'),
scanLocCount: _D('Taranan Lokasyon:', 'Scanned Locations:', 'Locais Varridos:'),
scanItemCount: _D('Toplam Eşya:', 'Total Items:', 'Total de Itens:'),
scanClose: _D('Kapat', 'Close', 'Fechar'),
// Scan prompts / logs
scanAskId: _D('Karakter ID girin:', 'Enter Character ID:', 'Digite o ID do Personagem:'),
scanBadId: _D('Geçerli ID girilmedi.', 'No valid ID entered.', 'Nenhum ID válido inserido.'),
scanVehList: _D('🔍 Araç listesi:', '🔍 Vehicle list:', '🔍 Lista de veículos:'),
scanVehUnit: _D('araç.', 'vehicles.', 'veículos.'),
scanHouseList: _D('🔍 Ev listesi:', '🔍 Housing list:', '🔍 Lista de moradias:'),
scanHouseUnit: _D('ev.', 'properties.', 'imóveis.'),
scanLogOk: _D('çeşit.', 'types.', 'tipos.'),
scanLogEmpty: _D('eşya yok.', 'no items.', 'sem itens.'),
scanStop: _D('🛑 DURDUR', '🛑 STOP', '🛑 PARAR'),
// Panel
panelTitle: '📦 Depot ' + GM_info.script.version,
dragHint: _D('⠿ Sürükle', '⠿ Drag', '⠿ Arrastar'),
btnSettings: _D('Panel Ayarları', 'Panel Settings', 'Configurações do Painel'),
btnBackup: _D('📤 Scripti Yedekle', '📤 Backup Script', '📤 Fazer Backup'),
btnRestore: _D('📥 Yedeği Yükle', '📥 Load Backup', '📥 Carregar Backup'),
catLabel: _D('Kategori CSV (Kategori,Eşya):', 'Category CSV (Category,Item):', 'CSV de Categorias (Categoria,Item):'),
catPlaceholder: _D('Kategori,Eşya Adı', 'Category,Item Name', 'Categoria,Nome do Item'),
btnCatSave: _D('💾 Kategorileri Güncelle', '💾 Update Categories', '💾 Atualizar Categorias'),
btnClearAll: _D('⚠️ Tüm Veriyi Sıfırla', '⚠️ Reset All Data', '⚠️ Redefinir Todos os Dados'),
btnSavePage: _D('📍 Sayfayı Kaydet', '📍 Save Page', '📍 Salvar Página'),
btnDelRecord: _D('🗑️ Kaydı Sil', '🗑️ Delete Record', '🗑️ Excluir Registro'),
btnInventory: _D('Envanter İşlemleri', 'Inventory Actions', 'Ações de Inventário'),
btnAutoScan: _D('🔄 OTOMATİK TARA', '🔄 AUTO SCAN', '🔄 VARREDURA AUTOMÁTICA'),
btnListManage: _D('📋 ENVANTERLERİ LİSTELE / YÖNET','📋 LIST / MANAGE INVENTORIES', '📋 LISTAR / GERENCIAR INVENTÁRIOS'),
btnDetailed: _D('📄 Detaylı CSV', '📄 Detailed CSV', '📄 CSV Detalhado'),
btnStockCSV: _D('📊 Stok & Fiyatlı CSV', '📊 Stock & Priced CSV', '📊 CSV de Estoque & Preços'),
btnImportCSV: _D('📥 CSV Yükle', '📥 Import CSV', '📥 Importar CSV'),
searchPH: _D('Envanterde ara (Örn: Haiku)...', 'Search inventory (e.g. Haiku)...', 'Buscar no inventário (ex: Haiku)...'),
// Alerts
alertNoItems: _D('Bu sayfada eşya bulunamadı.', 'No items found on this page.', 'Nenhum item encontrado nesta página.'),
alertDeleted: _D('Silindi.', 'Deleted.', 'Excluído.'),
alertNotFound: _D('Kayıt bulunamadı.', 'Record not found.', 'Registro não encontrado.'),
alertEnterData: _D('Veri girin.', 'Enter data.', 'Insira os dados.'),
alertCatFmt: _D("Format hatalı! 'Kategori,Eşya'", "Invalid format! 'Category,Item'", "Formato inválido! 'Categoria,Item'"),
alertClearConf: _D('Tüm DB sıfırlanacak!', 'All data will be reset!', 'Todos os dados serão redefinidos!'),
alertRestored: _D('Geri yüklendi.', 'Restored.', 'Restaurado.'),
alertInvalidFile:_D('Geçersiz dosya.', 'Invalid file.', 'Arquivo inválido.'),
// List
listEmpty: _D('Veritabanı boş.', 'Database empty.', 'Banco de dados vazio.'),
btnDelAll: _D('Tümünü Sil', 'Delete All', 'Excluir Tudo'),
btnDel: _D('SİL', 'DEL', 'EXC'),
confirmDel: _D('Bu kayıt silinsin mi?', 'Delete this record?', 'Excluir este registro?'),
// Search
noResults: _D('Sonuç bulunamadı.', 'No results found.', 'Nenhum resultado encontrado.'),
totalLabel: _D('Toplam', 'Total', 'Total'),
lastScanLabel: _D('Son tarama:', 'Last scan:', 'Última varredura:'),
btnCopy: _D('📋 Bu sonuçları kopyala', '📋 Copy these results', '📋 Copiar estes resultados'),
btnCopied: _D('✅ Kopyalandı', '✅ Copied', '✅ Copiado'),
noPriceLabel: _D('Teklif ediniz', 'Make an offer', 'Consultar preço'),
// clsLbl
clsPersonal: _D('Eşyalar', 'Items', 'Itens'),
clsVehicle: _D('Kişisel Araç', 'Personal Vehicle', 'Veículo Pessoal'),
clsHousing: _D('Ev', 'Housing', 'Moradia'),
clsArtist: _D('Sanatçı Aracı', 'Artist Vehicle', 'Veículo do Artista'),
minTooltip: _D('Paneli aç', 'Open panel', 'Abrir painel'),
btnMinimize: _D('Küçült', 'Minimize', 'Minimizar'),
btnClose: _D('Kapat', 'Close', 'Fechar'),
// Loc name fallbacks
locVehicleFb: _D('Kişisel Araç', 'Personal Vehicle', 'Veículo Pessoal'),
locLocaleFb: _D('Mekan', 'Locale', 'Local'),
locCharFb: _D('Karakter', 'Character', 'Personagem'),
locInvSuffix: _D('Envanteri', 'Inventory', 'Inventário'),
locArtistFb: _D('Grup Aracı', 'Artist Vehicle', 'Veículo do Artista'),
locUnknown: _D('Bilinmeyen', 'Unknown', 'Desconhecido'),
variantDefault: _D('Standart', 'Standard', 'Padrão'),
};
const _clDepot = (() => { try { const v = localStorage.getItem('ppc_lc_depot'); return v ? JSON.parse(v) : null; } catch { return null; } })();
const s = k => (_clDepot && _clDepot[k]) ? _clDepot[k] : (S[k] || k);
// GM Storage helpers
const gmGet = (k,def) => { try { const v=GM_getValue(k,null); return v?JSON.parse(v):def; } catch { return def; } };
const gmSet = (k,v) => GM_setValue(k, JSON.stringify(v));
const gmDel = (k) => GM_deleteValue(k);
// localStorage helpers (scan state only)
const lsGet = (k,def) => { try { const v=localStorage.getItem(k); return v?JSON.parse(v):def; } catch { return def; } };
const lsSet = (k,v) => localStorage.setItem(k, JSON.stringify(v));
const lsDel = (k) => localStorage.removeItem(k);
// Storage keys
const K = { db:'pop_inv_data', cat:'pop_cat_data', price:'pop_price_data', veh:'pop_vehicle_names', char:'pop_char_id', owner:'pop_owner_name', theme:'pop_theme', min:'pop_min', pw:'pop_panel_w', pos:'pop_panel_pos', posMin:'pop_panel_pos_min', scan:'pop_scan_state' };
// DB cache
let _db=null, _prices=null;
const getDB = () => _db || (_db=gmGet(K.db,{}));
const saveDB = (v) => { _db=v; gmSet(K.db,v); };
const getPrices = () => _prices || (_prices=gmGet(K.price,{}));
const savePrices = (v) => { _prices=v; gmSet(K.price,v); };
// Utilities
const today = () => { const d=new Date(); return `${String(d.getDate()).padStart(2,'0')}.${String(d.getMonth()+1).padStart(2,'0')}.${d.getFullYear()}`; };
const getCats = () => gmGet(K.cat,{Manuscripts:['Fıkra','Haiku'],Drugs:['Ağrı Kesici','Afrodizyak İksiri']});
const saveCats = (v) => gmSet(K.cat,v);
const getCat = (n) => { for (const [c,items] of Object.entries(getCats())) if (items.includes(n)) return c; return 'Diğer'; };
const theme = () => GM_getValue(K.theme,'')||'dark';
const priceKey = (n,v) => `${n}|||${v}`;
const esc = (v) => String(v).replace(/&/g,'&').replace(/"/g,'"');
const normV = (v) => v.replace(/\.\s*$/,'').trim();
const dlCSV = (content,name) => { const a=document.createElement('a'); a.href=URL.createObjectURL(new Blob([content],{type:'text/csv;charset=utf-8;'})); a.download=name; a.click(); };
const randDelay = () => 2000 + Math.floor(Math.random()*1500);
const getTitle = () => document.title.replace(/^.*?Popmundo\s*[-–]\s*/i,'').trim();
// Scan state
const getScan = () => lsGet(K.scan, {active:false,queue:[],index:0,logs:[]});
const saveScan = (st) => lsSet(K.scan, st);
// Scan: sayfa ayrıştırma
const getLocInfo = (u) => {
if (u.includes('/Character/Vehicle/')) {
const veh=gmGet(K.veh,{}), rel=u.replace(/^https?:\/\/[^/]+/,'');
return { name:veh[u]||veh[rel]||getTitle()||s('locVehicleFb'), type:'Araç' };
}
if (u.includes('/Locale/ItemsEquipment/')) {
const h2=document.querySelector('.localebox h2')?.innerText.trim();
const city=document.querySelector('.localebox .right a')?.innerText.trim();
return { name:h2?(city?`${h2} (${city})`:h2):(getTitle()||s('locLocaleFb')), type:'Mekan' };
}
if (u.includes('/Character/Items/')) {
const n=document.querySelector('.charPresBox h2')?.innerText.trim()||getTitle();
return { name:`${n||s('locCharFb')} ${s('locInvSuffix')}`, type:'Kişisel' };
}
if (u.includes('/Artist/VehicleItems/')) return { name:getTitle()||s('locArtistFb'), type:'Grup Aracı' };
return { name:s('locUnknown'), type:'Genel' };
};
const getOwner = () => {
const el=document.querySelector('.charPresBox h2');
if (el) { const n=el.innerText.trim(); GM_setValue(K.owner,n); return n; }
return GM_getValue(K.owner,'')||s('locCharFb');
};
const extractVariant = (anchor) => {
const td=anchor.closest('td')||anchor.parentElement, clone=td.cloneNode(true);
clone.querySelector('[id*="lnkItem"]')?.remove();
clone.querySelectorAll('.tvip-item-id, .tvis-ia-wrap').forEach(el => el.remove());
const cEm=Array.from(clone.querySelectorAll('em')).find(e=>/^x\d+/i.test(e.textContent.trim()));
if (cEm) cEm.remove();
return clone.textContent.replace(/\s+/g,' ').trim()||s('variantDefault');
};
const updatePage = () => {
const u=window.location.href, info=getLocInfo(u), owner=getOwner(), db=getDB(), map={};
document.querySelectorAll('tr.hoverable').forEach(row => {
const a=row.querySelector('a[id*="lnkItem"]'); if (!a) return;
const name=a.innerText.trim(), em=row.querySelector('em');
const count=em&&/^x\d+/i.test(em.textContent.trim())?(parseInt(em.textContent.replace(/[^\d]/g,''))||1):1;
const variant=extractVariant(a);
if (!map[name]) map[name]={variants:{}};
map[name].variants[variant]=(map[name].variants[variant]||0)+count;
});
const cnt=Object.keys(map).length;
if (cnt>0) {
if (!db[owner]) db[owner]={};
db[owner][u]={locType:info.name,locClass:info.type,url:u,lastUpdate:today(),
items:Object.entries(map).map(([n,d])=>({name:n,variants:d.variants}))};
_db=db; saveDB(db);
}
return cnt;
};
// Scan: modal & rapor
const ovStyle = 'position:fixed;inset:0;background:rgba(0,0,0,.8);z-index:9999999;display:flex;align-items:center;justify-content:center;';
const modalWrap = (inner) => '<div style="background:#1a1a1a;border-radius:10px;padding:24px;max-width:420px;width:92%;color:#e0e0e0;font-family:Arial,sans-serif;">'+inner+'</div>';
const showScanModal = (onConfirm) => {
const ov=document.createElement('div'); ov.style.cssText=ovStyle;
ov.innerHTML=modalWrap(
'<div style="font-size:15px;font-weight:bold;color:#3498db;margin-bottom:12px;">'+s('scanTitle')+'</div>'
+'<div style="display:flex;flex-direction:column;gap:10px;margin-bottom:14px;">'
+'<label style="display:flex;align-items:center;gap:8px;font-size:12px;cursor:pointer;"><input type="checkbox" id="sc-p" checked> '+s('scanPersonal')+'</label>'
+'<label style="display:flex;align-items:center;gap:8px;font-size:12px;cursor:pointer;"><input type="checkbox" id="sc-v" checked> '+s('scanVehicles')+'</label>'
+'<label style="display:flex;align-items:center;gap:8px;font-size:12px;cursor:pointer;"><input type="checkbox" id="sc-h" checked> '+s('scanHousing')+'</label>'
+'<label style="display:flex;align-items:center;gap:8px;font-size:12px;cursor:pointer;"><input type="checkbox" id="sc-a" checked> '+s('scanArtist')+'</label>'
+'</div>'
+'<div style="font-size:10px;color:#aaa;background:#222;border-radius:4px;padding:8px;margin-bottom:14px;">'+s('scanWarn')+'</div>'
+'<div style="display:flex;gap:8px;">'
+'<button id="sc-cancel" style="flex:1;padding:10px;background:none;color:#dc3545;border:1px solid #dc3545;border-radius:5px;cursor:pointer;font-weight:bold;">'+s('scanCancel')+'</button>'
+'<button id="sc-start" style="flex:2;padding:10px;background:#0056b3;color:white;border:none;border-radius:5px;cursor:pointer;font-weight:bold;">'+s('scanStart')+'</button>'
+'</div>'
);
document.body.appendChild(ov);
document.getElementById('sc-cancel').onclick=()=>ov.remove();
document.getElementById('sc-start').onclick=()=>{
const opts={personal:document.getElementById('sc-p').checked,vehicles:document.getElementById('sc-v').checked,housing:document.getElementById('sc-h').checked,artist:document.getElementById('sc-a').checked};
if (!Object.values(opts).some(Boolean)){alert(s('scanSelectOne'));return;}
ov.remove(); onConfirm(opts);
};
};
const showScanReport = (state) => {
const db=getDB(); let totI=0,totL=0;
Object.values(db).forEach(od=>{totL+=Object.keys(od).length;Object.values(od).forEach(e=>e.items.forEach(it=>Object.values(it.variants).forEach(c=>{totI+=Number(c)||0;})));});
const ov=document.createElement('div'); ov.style.cssText=ovStyle.replace('9999999','9999998');
ov.innerHTML=modalWrap(
'<div style="font-size:16px;font-weight:bold;color:#2ecc71;margin-bottom:12px;">'+s('scanDone')+'</div>'
+'<div style="background:#222;border-radius:5px;padding:10px;margin-bottom:10px;font-size:13px;">'
+'<div>'+s('scanLocCount')+' <b style="color:#2ecc71">'+totL+'</b></div>'
+'<div>'+s('scanItemCount')+' <b style="color:#2ecc71">'+totI+'</b></div></div>'
+'<div style="background:#222;border-radius:5px;padding:8px;max-height:180px;overflow-y:auto;font-size:11px;font-family:monospace;line-height:1.6;">'
+state.logs.map(l=>'<div style="color:'+(l.startsWith('✅')?'#2ecc71':l.startsWith('⚠️')?'#f39c12':'#e74c3c')+'">'+l+'</div>').join('')
+'</div><button id="sc-done" style="width:100%;margin-top:14px;padding:10px;background:#2ecc71;color:#111;border:none;border-radius:5px;cursor:pointer;font-weight:bold;">'+s('scanClose')+'</button>'
);
document.body.appendChild(ov);
document.getElementById('sc-done').onclick=()=>{ov.remove();location.href=`${location.origin}/World/Popmundo.aspx/Character/${state.charId}`;};
};
// Scan: keşif & adım
const discover = () => {
const url=window.location.href, base=`${location.origin}/World/Popmundo.aspx`;
let id=(url.match(/\/Character\/(?:Details|Items|Vehicles|Housing)\/(\d+)/)||[])[1]
||document.querySelector('a[href*="/Character/Details/"]')?.href.match(/\/(\d+)$/)?.[1]
||document.querySelector('a[href*="/Character/Items/"]')?.href.match(/\/(\d+)$/)?.[1]
||GM_getValue(K.char,'');
if (!id){const inp=prompt(s('scanAskId'));if(inp&&/^\d+$/.test(inp.trim()))id=inp.trim();else{alert(s('scanBadId'));return;}}
GM_setValue(K.char,id);
showScanModal(opts=>{
const q=[];
if(opts.personal)q.push(`${base}/Character/Items/${id}`);
if(opts.vehicles)q.push(`${base}/Character/Vehicles/${id}`);
if(opts.housing) q.push(`${base}/Character/Housing/${id}`);
if(opts.artist) q.push(`${base}/Artist/VehicleItems/`);
saveScan({active:true,queue:q,index:0,logs:[],charId:id});
location.href=q[0];
});
};
const runStep = () => {
if (!window.location.href.includes('/World/Popmundo.aspx/')) return;
let st=getScan(); if (!st.active) return;
setTimeout(()=>{
const u=window.location.href; let found=[];
if (u.includes('Character/Vehicles/')) {
const anchors=document.querySelectorAll('#tablevehicles a[href*="/Character/Vehicle/"]');
const veh=gmGet(K.veh,{});
anchors.forEach(a=>{if(a.href&&a.innerText.trim())veh[a.href]=a.innerText.trim();});
gmSet(K.veh,veh); found=Array.from(anchors).map(a=>a.href);
st.logs.push(`${s('scanVehList')} ${found.length} ${s('scanVehUnit')}`);
} else if (u.includes('Character/Housing/')) {
found=Array.from(document.querySelectorAll('#tablelocales a[href*="/Locale/"]'))
.filter(a=>/\/Locale\/\d+$/.test(a.getAttribute('href')))
.map(a=>{const id=a.getAttribute('href').match(/\/Locale\/(\d+)$/)?.[1];return id?`${location.origin}/World/Popmundo.aspx/Locale/ItemsEquipment/${id}`:null;})
.filter(Boolean);
st.logs.push(`${s('scanHouseList')} ${found.length} ${s('scanHouseUnit')}`);
} else {
const cnt=updatePage(), info=getLocInfo(u);
st.logs.push(cnt>0?`✅ ${info.name} (${info.type}): ${cnt} ${s('scanLogOk')}`:`⚠️ ${info.name}: ${s('scanLogEmpty')}`);
}
if (found.length) st.queue.splice(st.index+1,0,...found);
st.index++;
if (st.index<st.queue.length){saveScan(st);location.href=st.queue[st.index];}
else{const fs={...st};lsDel(K.scan);GM_setValue('pop_last_scan',today());showScanReport(fs);}
},randDelay());
};
// Panel: temalar
const CD = { bg:'#111',text:'#e0e0e0',border:'#444',hBg:'#1a1a1a',hBorder:'#444',subBg:'#1a1a1a',inBg:'#222',inText:'#eee',inBorder:'#555',detBg:'#1a1a1a',detBorder:'#444',owBg:'#2a2a2a',owText:'#f0ad4e',loc:'#5bc0de',lbl:'#aaa',muted:'#777',togBg:'#222',togText:'#ccc',togBorder:'#555',taBg:'#222',resBorder:'#2a2a2a',gtBg:'#1e3a1e',gtBorder:'#2ecc71',gtText:'#2ecc71',vtBg:'#1a2535',vtBorder:'#3498db',vtText:'#aad4f5',rowText:'#e0e0e0',countText:'#2ecc71',owText2:'#f0ad4e',link:'#5bc0de',sep:'#555',sec:'#95a5a6',dragHint:'#666',priceBg:'#1a1a1a',priceBorder:'#444',priceText:'#ccc' };
const CL = { bg:'#f5f5f5',text:'#222',border:'#bbb',hBg:'#e0e0e0',hBorder:'#ccc',subBg:'#e8e8e8',inBg:'#fff',inText:'#222',inBorder:'#aaa',detBg:'#ececec',detBorder:'#ccc',owBg:'#ddd',owText:'#555',loc:'#1a6896',lbl:'#555',muted:'#888',togBg:'#ddd',togText:'#333',togBorder:'#bbb',taBg:'#fff',resBorder:'#ddd',gtBg:'#d4edda',gtBorder:'#28a745',gtText:'#155724',vtBg:'#cce5ff',vtBorder:'#004085',vtText:'#004085',rowText:'#333',countText:'#155724',owText2:'#7d4f00',link:'#1a6896',sep:'#aaa',sec:'#555',dragHint:'#999',priceBg:'#fff',priceBorder:'#aaa',priceText:'#222' };
const C = () => theme()==='light' ? CL : CD;
// Panel: CSV export / import
const exportDetailed = () => {
const db=getDB(), ds=today();
let csv='\uFEFFCategory;Item Name;Variant;Qty;Owner;Class;Inventory Name;Date;URL\n';
Object.keys(db).forEach(owner=>Object.keys(db[owner]).forEach(url=>{
const e=db[owner][url], rel=url.replace(/^https?:\/\/[^/]+/,'');
e.items.forEach(item=>Object.entries(item.variants).forEach(([v,c])=>
csv+=`"${getCat(item.name)}";"${item.name}";"${v}";${c};"${owner}";"${e.locClass||'Genel'}";"${e.locType}";"${e.lastUpdate||ds}";"${rel}"\n`
));
}));
dlCSV(csv,`Detaylı_Envanter_CSV_${ds}.csv`);
};
const exportSummary = () => {
const db=getDB(), ds=today(), prices=getPrices(), sum={};
Object.values(db).forEach(od=>Object.values(od).forEach(e=>e.items.forEach(item=>
Object.entries(item.variants).forEach(([v,c])=>{
const k=priceKey(item.name,v);
if (!sum[k]) sum[k]={name:item.name,variant:v,count:0,cat:getCat(item.name)};
sum[k].count+=c;
})
)));
let csv='\uFEFFCategory;Item Name;Variant;Total Qty;Unit Price;Total Value\n',gt=0,gv=0;
Object.values(sum).forEach(x=>{
const rawP=prices[priceKey(x.name,x.variant)]||'0',up=parsePrice(rawP),tv=x.count*up;
gt+=x.count; gv+=tv; csv+=`"${x.cat}";"${x.name}";"${x.variant}";${x.count};${rawP};${tv}\n`;
});
csv+=`;;;"${gt}";;${gv}\n`;
dlCSV(csv,`Toplu_Stok_Fiyatli_CSV_${ds}.csv`);
};
const importCSV = (txt) => {
try {
const lines=txt.split(/\r?\n/),delim=txt.includes(';')?';':',',newDB={};
const h=lines[0].split(delim).map(x=>x.replace(/^"|"$/g,'').trim());
const [iN,iV,iO,iT,iU]=['Item Name','Variant','Owner','Inventory Name','URL'].map(x=>h.indexOf(x));
const iC=h.indexOf(h.find(x=>x.includes('Qty')));
for (let i=1;i<lines.length;i++) {
if (!lines[i].trim()) continue;
const c=lines[i].split(delim).map(x=>x.replace(/^"|"$/g,'').trim());
const owner=c[iO]||s('locUnknown'),url=c[iU]||'';
if (!newDB[owner]) newDB[owner]={};
if (!newDB[owner][url]) newDB[owner][url]={locType:c[iT],url,items:[]};
let ex=newDB[owner][url].items.find(it=>it.name===c[iN]);
if (!ex){ex={name:c[iN],variants:{}};newDB[owner][url].items.push(ex);}
ex.variants[c[iV]]=(ex.variants[c[iV]]||0)+(parseInt(c[iC])||0);
}
saveDB(newDB); location.reload();
} catch(e){alert(_D('Hata: ','Error: ','Erro: ')+e.message);}
};
// Panel: ayar yedek
const exportSettings = () => {
const out={}, gmKeys=[K.db,K.cat,K.price,K.veh,K.char,K.owner,K.theme];
gmKeys.forEach(k=>{const v=GM_getValue(k,null);if(v)out['gm_'+k]=v;});
const a=document.createElement('a'); a.href=URL.createObjectURL(new Blob([JSON.stringify(out,null,2)],{type:'application/json'})); a.download=`popmundo_yedek_${today()}.json`; a.click();
};
const importSettings = (txt) => {
try {
const d=JSON.parse(txt); if (typeof d!=='object') throw new Error();
Object.entries(d).forEach(([k,v])=>{ if (k.startsWith('gm_')) GM_setValue(k.slice(3),v); });
alert(s('alertRestored')); location.reload();
} catch { alert(s('alertInvalidFile')); }
};
// Panel: fiyat
const parsePrice = (str) => {
if (!str) return 0;
const v=String(str).trim().toLowerCase().replace(',','.');
const n=parseFloat(v); if (isNaN(n)) return 0;
if (v.endsWith('m')) return n*1000000;
if (v.endsWith('k')) return n*1000;
return n;
};
const doSavePrice = (inp) => {
const name=inp.dataset.name,variant=inp.dataset.variant; if (!name||!variant) return;
const raw=inp.value.trim(),p=getPrices(),k=priceKey(name,variant);
if (raw) p[k]=raw; else delete p[k]; savePrices(p);
const numVal=parsePrice(raw),count=parseInt(inp.dataset.count)||0;
const valEl=inp.closest('.pi-vt-row')&&inp.closest('.pi-vt-row').querySelector('.pi-val-span');
if (valEl) valEl.textContent=numVal>0?'= '+(numVal*count).toLocaleString('tr-TR'):'';
inp.style.borderColor='#2ecc71'; setTimeout(()=>{inp.style.borderColor='';},1000);
};
// Panel: liste & arama
let invListOpen=false;
const clsLbl=(c)=>({Kişisel:s('clsPersonal'),Araç:s('clsVehicle'),Mekan:s('clsHousing'),'Grup Aracı':s('clsArtist')}[c]||c||s('clsPersonal'));
const bindResults = (ld) => {
ld.addEventListener('click',(e)=>{
const btn=e.target.closest('[data-del-owner]');
const btnAll=e.target.closest('[data-del-all-owner]');
if (btnAll&&confirm(_D(btnAll.dataset.delAllOwner+' tüm verisi silinsin mi?','Delete all data for '+btnAll.dataset.delAllOwner+'?','Excluir todos os dados de '+btnAll.dataset.delAllOwner+'?'))) {
const db=getDB(); delete db[btnAll.dataset.delAllOwner]; saveDB(db); _db=null; showList(); return;
}
if (btn&&confirm(s('confirmDel'))){
const owner=btn.dataset.delOwner,url=btn.dataset.delUrl,db=getDB();
delete db[owner][url];
if (!Object.keys(db[owner]).length) delete db[owner];
saveDB(db); _db=null; showList();
}
});
ld.addEventListener('keydown',(e)=>{
if (e.key==='Enter'&&e.target.classList.contains('pi-price-inp')){e.preventDefault();doSavePrice(e.target);}
});
};
const showList = () => {
const ld=document.getElementById('pi-results'); if (!ld) return;
const db=getDB(),c=C(),owners=Object.keys(db).sort();
if (!owners.length){ld.innerHTML='<p style="color:#e74c3c;text-align:center;font-size:11px;">'+s('listEmpty')+'</p>';return;}
let html='';
owners.forEach(owner=>{
const totalCnt=Object.values(db[owner]).reduce((a,e)=>a+e.items.reduce((b,it)=>b+Object.values(it.variants).reduce((x,y)=>x+y,0),0),0);
html+='<div style="margin-bottom:6px;border:1px solid '+c.border+';background:'+c.subBg+';border-radius:4px;">'
+'<div style="background:'+c.owBg+';padding:4px 8px;color:'+c.owText+';font-size:11px;font-weight:bold;display:flex;justify-content:space-between;align-items:center;">'
+'<span>👤 '+esc(owner)+' <span style="font-weight:normal;opacity:.7;">['+totalCnt+']</span></span>'
+'<button data-del-all-owner="'+esc(owner)+'" style="background:none;color:#e74c3c;border:1px solid #e74c3c;padding:1px 6px;font-size:9px;cursor:pointer;border-radius:2px;">'+s('btnDelAll')+'</button></div>';
Object.keys(db[owner]).sort().forEach(url=>{
const e=db[owner][url],cnt=e.items.reduce((a,it)=>a+Object.values(it.variants).reduce((x,y)=>x+y,0),0);
html+='<div style="padding:4px 8px;border-bottom:1px solid '+c.resBorder+';display:flex;justify-content:space-between;align-items:center;">'
+'<a href="'+esc(url)+'" target="_blank" style="font-size:10px;color:'+c.loc+';text-decoration:none;">📍 '+esc(e.locType)+' <span style="color:'+c.muted+'">['+cnt+']</span></a>'
+'<button data-del-owner="'+esc(owner)+'" data-del-url="'+esc(url)+'" style="background:#a94442;color:white;border:none;padding:1px 5px;font-size:9px;cursor:pointer;border-radius:2px;">'+s('btnDel')+'</button></div>';
});
html+='</div>';
});
ld.innerHTML=html; bindResults(ld);
};
const renderSearch = (query) => {
const ld=document.getElementById('pi-results'); if (!ld) return;
if (!query){invListOpen?showList():(ld.innerHTML='');return;}
const db=getDB(),c=C(),prices=getPrices(),rows=[],vt={};
let grand=0;
Object.keys(db).forEach(owner=>Object.keys(db[owner]).forEach(url=>{
const e=db[owner][url],displayOwner=e.locClass==='Araç'?e.locType:owner;
e.items.forEach(item=>{
if (!item.name.toLowerCase().includes(query.toLowerCase())) return;
Object.entries(item.variants).forEach(([v,cnt])=>{
const nv=normV(v), k=priceKey(item.name,nv);
if (!vt[k]) vt[k]={name:item.name,variant:nv,count:0};
vt[k].count+=cnt; grand+=cnt;
rows.push({name:item.name,variant:nv,count:cnt,displayOwner,locClass:e.locClass,locType:e.locType,url});
});
});
}));
if (!rows.length){ld.innerHTML='<p style="font-size:10px;color:'+c.muted+';padding:4px;">'+s('noResults')+'</p>';return;}
const lastScan=GM_getValue('pop_last_scan','')||'—';
let html='<div style="background:'+c.gtBg+';border:1px solid '+c.gtBorder+';border-radius:4px;padding:6px 10px;margin-bottom:6px;font-size:12px;color:'+c.gtText+';display:flex;justify-content:space-between;align-items:center;">'
+'<b>'+s('totalLabel')+' "'+esc(query)+'": '+grand+'</b>'
+'<span style="font-size:10px;font-weight:normal;opacity:.7;">'+s('lastScanLabel')+' '+lastScan+'</span></div>';
html+='<div style="background:'+c.vtBg+';border:1px solid '+c.vtBorder+';border-radius:4px;padding:6px 10px;margin-bottom:8px;font-size:11px;">';
const vtList=Object.values(vt);
vtList.forEach(x=>{
const pk=priceKey(x.name,x.variant),raw=prices[pk]||'';
const numVal=parsePrice(raw),valTxt=numVal>0?'= '+(numVal*x.count).toLocaleString('tr-TR'):'';
html+='<div class="pi-vt-row" style="display:flex;align-items:center;gap:6px;padding:3px 0;border-bottom:1px solid '+c.vtBorder+'44;color:'+c.vtText+';">'
+'<span style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"><b>'+esc(x.name)+'</b> <span style="opacity:.7;font-size:10px;">'+esc(x.variant)+'</span> <span style="color:'+c.gtText+';font-weight:bold;">x'+x.count+'</span></span>'
+'<input type="text" placeholder="30k / 2m" value="'+esc(raw)+'" data-count="'+x.count+'" data-name="'+esc(x.name)+'" data-variant="'+esc(x.variant)+'" class="pi-price-inp"'
+' style="width:80px;font-size:10px;padding:2px 4px;background:'+c.priceBg+';color:'+c.priceText+';border:1px solid '+c.priceBorder+';border-radius:3px;flex-shrink:0;">'
+'<span class="pi-val-span" style="font-size:10px;color:'+c.countText+';min-width:70px;flex-shrink:0;">'+valTxt+'</span></div>';
});
html+='<button id="pi-copy-btn" style="width:100%;margin-top:6px;padding:5px;background:#444;color:#ccc;border:1px solid #666;border-radius:3px;cursor:pointer;font-size:10px;">'+s('btnCopy')+'</button>';
html+='</div><div style="font-size:10px;">';
rows.forEach(r=>{
const charIdM = r.url.match(/\/Character\/(?:Items|ItemsEquipment)\/(\d+)/);
const charUrl = charIdM ? r.url.replace(/\/Character\/(?:Items|ItemsEquipment)\/\d+/, '/Character/Details/'+charIdM[1]) : null;
const ownerHtml = charUrl
? '<a href="'+esc(charUrl)+'" target="_blank" style="color:'+c.owText2+';text-decoration:none;font-weight:600;">'+esc(r.displayOwner)+'</a>'
: '<span style="color:'+c.owText2+';font-weight:600;">'+esc(r.displayOwner)+'</span>';
html+='<div style="padding:5px 4px;border-bottom:1px solid '+c.resBorder+';display:flex;flex-direction:column;gap:2px;">'
+'<div style="display:flex;align-items:baseline;gap:4px;flex-wrap:wrap;">'
+'<span style="color:'+c.rowText+';font-size:10px;font-weight:600;word-break:break-word;">'+esc(r.name)+'</span>'
+'<span style="color:'+c.muted+';font-size:9px;">'+esc(r.variant)+'</span>'
+'<span style="color:'+c.countText+';font-weight:bold;font-size:10px;margin-left:auto;">x'+r.count+'</span>'
+'</div>'
+'<div style="display:flex;align-items:center;gap:4px;flex-wrap:wrap;font-size:9px;">'
+ownerHtml
+'<span style="color:'+c.sep+';">→</span>'
+'<a href="'+esc(r.url)+'" target="_blank" style="color:'+c.link+';text-decoration:none;">'+esc(r.locType)+'</a>'
+'</div>'
+'</div>';
});
ld.innerHTML=html+'</div>';
bindResults(ld);
document.getElementById('pi-copy-btn')?.addEventListener('click',()=>{
const txt=vtList.map(x=>{const raw=prices[priceKey(x.name,x.variant)]||'';return x.name+' '+x.variant+': x'+x.count+(raw?' - '+raw:' - '+s('noPriceLabel'));}).join('\n');
navigator.clipboard.writeText(txt).then(()=>{const b=document.getElementById('pi-copy-btn');if(b){b.textContent=s('btnCopied');setTimeout(()=>{b.textContent=s('btnCopy');},1500);}});
});
};
// Panel: UI
function _createDepotFAB() {
if (document.getElementById('pi-fab')) return;
if (GM_getValue('dp_pc_connected', false)) return; // PC bağlıysa FAB gösterme
// Position right of MissionAid float if present
const maFloat = document.getElementById('qrFloat');
const rightOffset = maFloat ? (window.innerWidth - maFloat.getBoundingClientRect().left + 8) : 14;
const fab = document.createElement('button');
fab.id = 'pi-fab'; fab.type = 'button';
fab.style.cssText = 'position:fixed;bottom:18px;right:'+rightOffset+'px;z-index:999990;width:40px;height:40px;border-radius:50%;background:#6f42c1;color:#fff;font-size:20px;border:2px solid #fff;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.35);display:flex;align-items:center;justify-content:center;font-family:inherit;line-height:1';
fab.title = _D('Envanter','Inventory','Inventário');
fab.innerHTML = '<span style="pointer-events:none">📦</span>';
fab.onclick = () => { fab.remove(); createUI(); };
document.body.appendChild(fab);
}
const createUI = () => {
if (document.getElementById('pi-panel')) return;
const c=C(),w=Math.min(gmGet(K.pw,340),window.innerWidth-8);
const panel=document.createElement('div'); panel.id='pi-panel';
const defaultRight = () => ({ right: 10, top: Math.round(window.innerHeight / 2) - 20 });
const pos = gmGet(K.pos, null);
const posStyle = pos
? 'left:'+pos.left+'px;top:'+pos.top+'px;'
: 'right:10px;top:'+Math.round(window.innerHeight/2-200)+'px;';
const th=theme(), ts='background:'+c.togBg+';color:'+c.togText+';border:1px solid '+c.togBorder;
const thD=th==='dark'?'background:#333;color:#fff;border:2px solid #f0ad4e':ts;
const thL=th==='light'?'background:#fff;color:#222;border:2px solid #f0ad4e':ts;
const mkLangBtn=(lang,label)=>{
const active=LANG===lang;
return '<button data-lang="'+lang+'" style="flex:1;padding:6px 4px;font-size:11px;border-radius:4px;cursor:pointer;font-weight:'+(active?'bold':'normal')+';background:'+(active?'#f0ad4e':c.togBg)+';color:'+(active?'#111':c.togText)+';border:2px solid '+(active?'#f0ad4e':c.togBorder)+';transition:all .15s;">'+label+'</button>';
};
panel.style.cssText='position:fixed;'+posStyle+'width:'+w+'px;min-width:220px;max-width:calc(100vw - 8px);z-index:999999;background:'+c.bg+';color:'+c.text+';border:2px solid '+c.border+';border-radius:10px;padding:0;font-family:Arial,sans-serif;box-shadow:0 12px 40px rgba(0,0,0,.5);max-height:88vh;overflow-y:auto;overflow-x:hidden;word-break:break-word;';
panel.innerHTML=
// HEADER — title + drag hint + minimize
'<div id="pi-drag" style="background:'+c.hBg+';border-radius:8px 8px 0 0;padding:10px 14px;border-bottom:2px solid '+c.hBorder+';display:flex;justify-content:space-between;align-items:center;cursor:grab;user-select:none;">'
+'<span style="font-size:14px;font-weight:bold;color:#f0ad4e;">'+s('panelTitle')+'</span>'
+'<div style="display:flex;gap:6px;align-items:center;">'
+('ontouchstart' in window ? '' : '<span style="font-size:10px;color:'+c.dragHint+';border:1px dashed '+c.dragHint+';padding:2px 5px;border-radius:3px;">'+s('dragHint')+'</span>')
+'<button id="pi-min" style="'+ts+';border-radius:6px;padding:3px 8px;cursor:pointer;font-size:11px;display:flex;align-items:center;gap:4px;white-space:nowrap;flex-shrink:0;">'
+(GM_getValue('dp_pc_connected',false)?'✕ '+s('btnClose'):'📦 '+s('btnMinimize'))
+'</button>'
+'</div></div>'
+'<div style="padding:8px 12px 0;">'
// ACCORDION ROW — two buttons side by side
+'<div style="display:flex;gap:6px;margin-bottom:6px;">'
+'<button id="pi-tog-cfg" style="flex:1;padding:8px 6px;'+ts+';border-radius:5px;cursor:pointer;font-weight:bold;font-size:11px;text-align:center;">⚙️ '+s('btnSettings')+' ▾</button>'
+'<button id="pi-tog-det" style="flex:1;padding:8px 6px;'+ts+';border-radius:5px;cursor:pointer;font-weight:bold;font-size:11px;text-align:center;">📋 '+s('btnInventory')+' ▾</button>'
+'</div>'
// SETTINGS PANEL
+'<div id="pi-cfg" style="display:none;background:'+c.detBg+';padding:10px;border-radius:5px;border:1px solid '+c.detBorder+';margin-bottom:8px;">'
// Lang buttons — first row inside settings
+'<div id="pi-lang-btns" style="display:flex;gap:5px;margin-bottom:10px;">'
+mkLangBtn('TR','🇹🇷 Türkçe')+mkLangBtn('EN','🇬🇧 English')+mkLangBtn('PT-BR','🇧🇷 Português')
+'</div>'
+'<div style="display:flex;gap:6px;margin-bottom:10px;">'
+'<button id="pi-th-dark" style="flex:1;padding:7px;border-radius:4px;cursor:pointer;font-size:11px;font-weight:bold;'+thD+'">🌙 Dark</button>'
+'<button id="pi-th-light" style="flex:1;padding:7px;border-radius:4px;cursor:pointer;font-size:11px;font-weight:bold;'+thL+'">☀️ Light</button></div>'
+'<div style="display:flex;gap:5px;margin-bottom:6px;">'
+'<button id="pi-exp-set" style="flex:1;padding:8px;background:#17a2b8;color:white;border:none;border-radius:3px;cursor:pointer;font-size:11px;">'+s('btnBackup')+'</button>'
+'<button id="pi-imp-set" style="flex:1;padding:8px;background:#6c757d;color:white;border:none;border-radius:3px;cursor:pointer;font-size:11px;">'+s('btnRestore')+'</button></div>'
+'<label style="color:'+c.lbl+';font-size:10px;">'+s('catLabel')+'</label>'
+'<textarea id="pi-cat-txt" placeholder="'+s('catPlaceholder')+'" style="width:100%;height:50px;font-size:10px;background:'+c.taBg+';color:'+c.text+';border:1px solid '+c.inBorder+';border-radius:3px;resize:vertical;margin-top:4px;box-sizing:border-box;"></textarea>'
+'<button id="pi-cat-save" style="width:100%;margin-top:5px;background:#444;color:white;border:none;padding:6px;font-size:10px;border-radius:3px;cursor:pointer;">'+s('btnCatSave')+'</button>'
+'<button id="pi-clear" style="width:100%;margin-top:8px;padding:7px;background:none;color:#dc3545;border:1px solid #dc3545;border-radius:4px;cursor:pointer;font-size:10px;">'+s('btnClearAll')+'</button>'
+'</div>'
// INVENTORY PANEL
+'<div id="pi-det" style="display:none;background:'+c.detBg+';padding:10px;border-radius:5px;border:1px solid '+c.detBorder+';margin-bottom:8px;">'
+'<button id="pi-scan" style="width:100%;padding:10px;background:#0056b3;color:white;border:none;border-radius:5px;cursor:pointer;font-weight:bold;margin-bottom:8px;">'+s('btnAutoScan')+'</button>'
+'<button id="pi-list" style="width:100%;background:#17a2b8;color:white;border:none;padding:8px;font-weight:bold;border-radius:5px;cursor:pointer;margin-bottom:8px;">'+s('btnListManage')+'</button>'
+'<div style="display:flex;gap:5px;">'
+'<button id="pi-exp-det" style="flex:1;padding:8px;background:#6c757d;color:white;border:none;border-radius:3px;cursor:pointer;font-size:11px;">'+s('btnDetailed')+'</button>'
+'<button id="pi-exp-sum" style="flex:1;padding:8px;background:#6c757d;color:white;border:none;border-radius:3px;cursor:pointer;font-size:11px;">'+s('btnStockCSV')+'</button>'
+'<button id="pi-imp-csv" style="flex:1;padding:8px;background:#6c757d;color:white;border:none;border-radius:3px;cursor:pointer;font-size:11px;">'+s('btnImportCSV')+'</button>'
+'</div></div>'
// SAVE / DELETE ROW
+'<div style="display:flex;gap:6px;margin-bottom:8px;">'
+'<button id="pi-save" style="flex:3;background:#218838;color:white;border:none;padding:10px;font-weight:bold;border-radius:5px;cursor:pointer;">'+s('btnSavePage')+'</button>'
+'<button id="pi-del" style="flex:1;background:none;color:#f39c12;border:1px solid #f39c12;border-radius:4px;cursor:pointer;font-size:10px;">'+s('btnDelRecord')+'</button>'
+'</div>'
// SEARCH
+'<input type="text" id="pi-search" placeholder="'+s('searchPH')+'" style="width:100%;padding:10px;background:'+c.inBg+';color:'+c.inText+';border:2px solid #3498db;border-radius:5px;box-sizing:border-box;outline:none;">'
+'<div id="pi-results" style="margin-top:10px;"></div>'
+'</div>';
document.body.appendChild(panel);
// Dil butonları — document delegation, pi-cfg içinde display:none sorununu aşar
document.addEventListener('click',(e)=>{
const btn=e.target.closest('#pi-lang-btns [data-lang]'); if(!btn)return;
document.cookie='ppm_lang='+btn.dataset.lang+';path=/;domain=.popmundo.com;max-age=31536000';
location.reload();
});
// Accordion: birine tıklayınca diğeri kapanır
const togMutual=(bA,dA,bB,dB)=>{
const btnA=document.getElementById(bA),divA=document.getElementById(dA);
const btnB=document.getElementById(bB),divB=document.getElementById(dB);
if(!btnA||!btnB) return;
const setArrow=(btn,open)=>{btn.textContent=btn.textContent.replace(open?'▴':'▾',open?'▾':'▴');};
btnA.addEventListener('click',()=>{
const openA=divA.style.display!=='none';
divA.style.display=openA?'none':'block'; setArrow(btnA,openA);
if(!openA){divB.style.display='none'; if(btnB.textContent.includes('▴'))setArrow(btnB,true);}
});
btnB.addEventListener('click',()=>{
const openB=divB.style.display!=='none';
divB.style.display=openB?'none':'block'; setArrow(btnB,openB);
if(!openB){divA.style.display='none'; if(btnA.textContent.includes('▴'))setArrow(btnA,true);}
});
};
togMutual('pi-tog-cfg','pi-cfg','pi-tog-det','pi-det');
// Sol kenardan resize
const rh=document.createElement('div');
rh.style.cssText='position:absolute;top:0;left:0;width:8px;height:100%;cursor:ew-resize;z-index:2;';
panel.appendChild(rh);
let resizing=false,startX=0,startW=0;
rh.addEventListener('mousedown',(e)=>{resizing=true;startX=e.clientX;startW=panel.offsetWidth;e.preventDefault();});
document.addEventListener('mousemove',(e)=>{if(!resizing)return;const nw=Math.max(220,Math.min(window.innerWidth-8,startW-(e.clientX-startX)));panel.style.width=nw+'px';});
document.addEventListener('mouseup',()=>{if(!resizing)return;resizing=false;gmSet(K.pw,panel.offsetWidth);});
// Sürükleme
let drag=false,ox=0,oy=0;
document.getElementById('pi-drag').addEventListener('mousedown',(e)=>{
if(e.target.closest('button'))return;
drag=true; panel.style.cursor='grabbing';
const rect=panel.getBoundingClientRect();
ox=rect.left-e.clientX; oy=rect.top-e.clientY;
});
document.addEventListener('mousemove',(e)=>{
if(!drag)return;
panel.style.left=Math.max(0,e.clientX+ox)+'px';
panel.style.top=Math.max(0,e.clientY+oy)+'px';
panel.style.right='auto'; panel.style.bottom='auto';
});
document.addEventListener('mouseup',()=>{
if(!drag)return; drag=false; panel.style.cursor='';
gmSet(K.pos,{left:panel.offsetLeft,top:panel.offsetTop});
});
const fileInput=(accept,cb)=>{const i=document.createElement('input');i.type='file';i.accept=accept;i.onchange=e=>{const r=new FileReader();r.onload=ev=>cb(ev.target.result);r.readAsText(e.target.files[0]);};i.click();};
const on=(id,fn)=>document.getElementById(id)&&document.getElementById(id).addEventListener('click',fn);
on('pi-min',()=>{
panel.remove();
if (!GM_getValue('dp_pc_connected', false)) _createDepotFAB();
// If connected: PopControl button brings it back — no FAB needed
});
on('pi-save',()=>{const cnt=updatePage();if(cnt>0){alert(_D(cnt+' çeşit eşya kaydedildi.',cnt+' item type(s) saved.',cnt+' tipo(s) de item salvos.'));location.reload();}else alert(s('alertNoItems'));});
on('pi-del',()=>{const u=location.href,db=getDB();let f=false;Object.keys(db).forEach(o=>{if(db[o]&&db[o][u]){delete db[o][u];f=true;}});if(f){saveDB(db);alert(s('alertDeleted'));location.reload();}else alert(s('alertNotFound'));});
on('pi-scan',()=>discover());
on('pi-list',()=>{invListOpen?((document.getElementById('pi-results').innerHTML=''),invListOpen=false):(showList(),invListOpen=true);});
on('pi-exp-det',exportDetailed);
on('pi-exp-sum',exportSummary);
on('pi-imp-csv',()=>fileInput('.csv',importCSV));
on('pi-exp-set',exportSettings);
on('pi-imp-set',()=>fileInput('.json',importSettings));
on('pi-th-dark',()=>{GM_setValue(K.theme,'dark');panel.remove();createUI();});
on('pi-th-light',()=>{GM_setValue(K.theme,'light');panel.remove();createUI();});
document.getElementById('pi-search').addEventListener('input',(e)=>renderSearch(e.target.value.trim()));
on('pi-cat-save',()=>{
const raw=document.getElementById('pi-cat-txt').value; if(!raw.trim())return alert(s('alertEnterData'));
const nc={};raw.split('\n').forEach(line=>{const p=line.includes('\t')?line.split('\t'):line.split(',');if(p.length>=2){const cat=p[0].trim(),it=p[1].trim();if(!nc[cat])nc[cat]=[];nc[cat].push(it);}});
if(Object.keys(nc).length){saveCats(nc);alert(_D(Object.keys(nc).length+' kategori güncellendi!',Object.keys(nc).length+' category/categories updated!',Object.keys(nc).length+' categoria(s) atualizada(s)!'));}else alert(s('alertCatFmt'));
});
on('pi-clear',()=>{if(confirm(s('alertClearConf'))){gmDel(K.db);location.reload();}});
};
// Scan: oturum başlat
const sc=getScan();
if (sc.active && window.location.href.includes('/World/Popmundo.aspx/')) {
const btn=document.createElement('button');
const curName=sc.queue[sc.index]?sc.queue[sc.index].split('/').pop():'';
btn.textContent=`${s('scanStop')} (${sc.index}/${sc.queue.length}) — ${curName}`;
btn.style.cssText='position:fixed;top:10px;left:50%;transform:translateX(-50%);z-index:999998;padding:10px 20px;background:#dc3545;color:white;border:none;border-radius:6px;cursor:pointer;font-weight:bold;font-size:13px;';
btn.onclick=()=>{lsDel(K.scan);location.reload();};
document.body.appendChild(btn);
if (document.readyState==='complete') runStep();
else window.addEventListener('load',runStep);
}
// EN strings for PopControl export
window.__ppcStrDepot = {"scanTitle": "🔄 Auto Scan", "scanPersonal": "👤 Personal Items", "scanVehicles": "🚗 Personal Vehicles", "scanHousing": "🏠 Housing", "scanArtist": "🎵 Artist / Tour Vehicle", "scanWarn": "⚠️ Tabs will change automatically during scan.", "scanCancel": "Cancel", "scanStart": "▶ Start Scan", "scanSelectOne": "Select at least one category.", "scanDone": "✅ Scan Complete", "scanLocCount": "Scanned Locations:", "scanItemCount": "Total Items:", "scanClose": "Close", "scanAskId": "Enter Character ID:", "scanBadId": "No valid ID entered.", "scanVehList": "🔍 Vehicle list:", "scanVehUnit": "vehicles.", "scanHouseList": "🔍 Housing list:", "scanHouseUnit": "properties.", "scanLogOk": "types.", "scanLogEmpty": "no items.", "scanStop": "🛑 STOP", "panelTitle": "📦 Depot", "dragHint": "⠿ Drag", "btnSettings": "Panel Settings", "btnBackup": "📤 Backup Script", "btnRestore": "📥 Load Backup", "catLabel": "Category CSV (Category,Item):", "catPlaceholder": "Category,Item Name", "btnCatSave": "💾 Update Categories", "btnClearAll": "⚠️ Reset All Data", "btnSavePage": "📍 Save Page", "btnDelRecord": "🗑️ Delete Record", "btnInventory": "Inventory Actions", "btnAutoScan": "🔄 AUTO SCAN", "btnListManage": "📋 LIST / MANAGE INVENTORIES", "btnDetailed": "📄 Detailed CSV", "btnStockCSV": "📊 Stock & Priced CSV", "btnImportCSV": "📥 Import CSV", "searchPH": "Search inventory (e.g. Haiku)...", "alertNoItems": "No items found on this page.", "alertDeleted": "Deleted.", "alertNotFound": "Record not found.", "alertEnterData": "Enter data.", "alertClearConf": "All data will be reset!", "alertRestored": "Restored.", "alertInvalidFile": "Invalid file.", "listEmpty": "Database empty.", "btnDelAll": "Delete All", "btnDel": "DEL", "confirmDel": "Delete this record?", "noResults": "No results found.", "totalLabel": "Total", "lastScanLabel": "Last scan:", "btnCopy": "📋 Copy these results", "btnCopied": "✅ Copied", "noPriceLabel": "Make an offer", "clsPersonal": "Items", "clsVehicle": "Personal Vehicle", "clsHousing": "Housing", "clsArtist": "Artist Vehicle", "minTooltip": "Open panel", "btnMinimize": "Minimize", "btnClose": "Close", "locVehicleFb": "Personal Vehicle", "locLocaleFb": "Locale", "locCharFb": "Character", "locInvSuffix": "Inventory", "locArtistFb": "Artist Vehicle", "locUnknown": "Unknown", "variantDefault": "Standard"};
window.__ppcStrDepot.panelTitle = '📦 Depot ' + GM_info.script.version;
// PopControl hazır olana kadar bekler
function _waitPC(cb,n){n=n||0;if(unsafeWindow.PopControl){cb();return;}if(n<20)setTimeout(function(){_waitPC(cb,n+1);},300);}
// Auto-connect to PopControl if available
_waitPC(function() {
unsafeWindow.PopControl.register({
id:'depot', icon:'📦', label:_D('Envanter','Inventory','Inventário'),
strings: window.__ppcStrDepot || {},
buttons:[{icon:'📦', label:_D('Depot','Depot','Depot'), onClick:function(){
var p=document.getElementById('pi-panel');
if (p) { p.style.display = p.style.display===''?'none':''; }
else { createUI(); }
}}],
onUndo:function(){
GM_setValue('dp_pc_connected', false);
document.getElementById('pi-panel')?.remove();
_createDepotFAB();
},
});
document.getElementById('pi-fab')?.remove();
GM_setValue('dp_pc_connected', true);
});
_createDepotFAB();
})();