import{read as e}from"./exif-7f3a.js";const t={pad:14,gap:18,size:13,weight:"500",radius:2},o=["shutter","aperture","iso","focal","lens","body"],n=[1,2,3,4,5,6,8,10,13,15,20,25,30,40,50,60,80,100,125,160,200,250,320,400,500,640,800,1e3,1250,1600,2e3,2500,3200,4e3,5e3,6400,8e3];export async function settings(t){const o=await e(t);if(!o)throw new Error("no exif: "+t);return{body:o.Model||o.Make||"unknown",lens:o.LensModel||o.LensSpecification||null,focal:Math.round(o.FocalLength||0),equiv:Math.round((o.FocalLength||0)*(o.CropFactor||1)),shutter:o.ExposureTime||null,aperture:o.FNumber||null,iso:o.ISO||o.ISOSpeedRatings||null,bias:o.ExposureBiasValue||0,mode:o.ExposureProgram||0,shot:o.DateTimeOriginal?+new Date(o.DateTimeOriginal):0,px:[o.PixelXDimension||0,o.PixelYDimension||0]}}export function fraction(e){if(!e)return null;if(e>=1)return e.toFixed(e%1?1:0)+"s";const t=1/e;let o=n[0];for(const e of n)Math.abs(e-t)<Math.abs(o-t)&&(o=e);return"1/"+o}export function stop(e){if(!e)return null;const t=Math.round(10*e)/10;return"f/"+(t%1==0?t.toFixed(0):t.toFixed(1))}export function caption(e,t=o){const n={shutter:fraction(e.shutter),aperture:stop(e.aperture),iso:e.iso?"ISO "+e.iso:null,focal:e.focal?e.focal+"mm":null,lens:e.lens,body:e.body};return t.map((e=>n[e])).filter(Boolean)}export function plate(e,o,n={}){const r={...t,...n},i=e.getContext("2d");if(!i)return e;const a=n.dpr||globalThis.devicePixelRatio||1;i.save(),i.scale(a,a),i.font=r.weight+" "+r.size+"px IBMPlexMono, monospace",i.textBaseline="top";const s=caption(o,n.fields),{width:l,widths:u}=function(e,t,o){let n=0;const r=t.map((t=>{const o=e.measureText(t).width;return n+=o,o}));return{width:n+o*(t.length-1),widths:r}}(i,s,r.gap),p=null==n.x?2*r.pad:n.x,c=null==n.y?e.height/a-r.size-3*r.pad:n.y;i.fillStyle=n.ground||"rgba(10,11,13,.72)",i.fillRect(p-r.pad,c-r.pad/2,l+2*r.pad,r.size+r.pad),i.fillStyle=n.ink||"#f4f2ed";let d=p;return s.forEach(((e,t)=>{i.fillText(e,d,c),d+=u[t]+r.gap})),i.restore(),e}export function fit(e,t){const o=Math.min(1,t/Math.max(e.width,e.height));return[Math.round(e.width*o),Math.round(e.height*o)]}export async function burn(e,t,o={}){const[n,r]=fit(e,o.max||2048),i=new OffscreenCanvas(n,r),a=i.getContext("2d");return a.imageSmoothingQuality="high",a.drawImage(e,0,0,n,r),plate(i,t,o),i}export function toFile(e,t="print",o=.94){return new Promise(((n,r)=>{const i=e=>e?n(new File([e],t+".jpg",{type:"image/jpeg"})):r(new Error("encode failed"));e.convertToBlob?e.convertToBlob({type:"image/jpeg",quality:o}).then(i,r):e.toBlob(i,"image/jpeg",o)}))}export const STOPS=[1,1.2,1.4,1.6,1.8,2,2.2,2.5,2.8,3.2,3.5,4,4.5,5,5.6,6.3,7.1,8,9,10,11,13,14,16,18,20,22,25,29,32];export const CROP={"ILCE-7RM5":1,"ILCE-7M4":1,"ILCE-9M3":1,"ILCE-6700":1.5,"ILCE-7CR":1,"ZV-E1":1,"DSC-RX100M7":2.73,"ILCA-99M2":1,"X-T5":1.5,X100V:1.5,GFX100S:.79,"EOS R5":1,"EOS R7":1.6,"Z 8":1,"Z fc":1.5,"DMC-GH5":2};export const PROGRAM=["not defined","manual","program","aperture priority","shutter priority","creative","action","portrait","landscape"];export const PRESETS={print:{pad:18,gap:22,size:15,fields:["shutter","aperture","iso","focal"]},web:{pad:12,gap:16,size:12,fields:["shutter","aperture","iso"]},contact:{pad:8,gap:10,size:10,fields:["shutter","aperture"]},full:{pad:16,gap:20,size:13,fields:["body","lens","focal","shutter","aperture","iso"]}};export function nearest(e,t){return t.reduce(((t,o)=>Math.abs(o-e)<Math.abs(t-e)?o:t),t[0])}export function equivalent(e){const t=CROP[e.body]||1;return Math.round((e.focal||0)*t)}export function describe(e){const t=PROGRAM[e.mode]||PROGRAM[0],o=e.bias?(e.bias>0?"+":"")+e.bias.toFixed(1)+"ev":null;return[e.body,e.lens,equivalent(e)+"mm",t,o].filter(Boolean).join(" / ")}export function preset(e){return{...t,...PRESETS[e]||PRESETS.web}}const e=require("crypto"),t=require("fs"),r=require("path"),s=/\.(arw|cr2|cr3|nef|orf|raf|rw2|dng|jpe?g|tiff?|heic)$/i,a=/\.(xmp|aae|thm|lrv)$/i,i=1<<20,n=[250,1e3,4e3];function o(e){return new Promise((t=>setTimeout(t,e)))}async function c(e,t){let r;for(let e=0;e<=3;e++)try{return await t(e)}catch(t){if(r=t,3===e||"ENOSPC"===t.code)break;await o(n[Math.min(e,n.length-1)])}throw Object.assign(new Error(e+": "+r.message),{cause:r})}function f(r){return new Promise(((s,a)=>{const n=e.createHash("sha256"),o=t.createReadStream(r,{highWaterMark:i});o.on("data",(e=>n.update(e))),o.on("error",a),o.on("end",(()=>s(n.digest("hex"))))}))}async function u(e,s){await t.promises.mkdir(r.dirname(s),{recursive:!0});const a=s+".part";await t.promises.copyFile(e,a);const[i,n]=await Promise.all([f(e),f(a)]);if(i!==n)throw await t.promises.unlink(a).catch((()=>{})),new Error("verify failed: "+r.basename(e));return await t.promises.rename(a,s),i}function l(e,t,s){const a=new Date(t.mtimeMs),i=String(a.getMonth()+1).padStart(2,"0"),n=String(a.getDate()).padStart(2,"0");return r.join(e,String(a.getFullYear()),i+"-"+n,s)}async function*m(e){for(const i of await t.promises.readdir(e,{withFileTypes:!0})){const t=r.join(e,i.name);i.isDirectory()?yield*m(t):(s.test(i.name)||a.test(i.name))&&(yield t)}}function p(e,t){const r=t.frames(e.serial);return!!r.length&&r.every((e=>e.copies>=2&&e.verified))}module.exports={run:async function(e,s,a){const i={copied:0,skipped:0,bytes:0,failed:[]};for await(const n of m(e.mount)){const o=await t.promises.stat(n),m=await f(n);if(a.has(m))i.skipped++;else try{for(const e of s){const t=l(e,o,r.basename(n));await c(r.basename(n),(()=>u(n,t)))}a.put(m,{card:e.serial,name:r.basename(n),size:o.size,copies:s.length,verified:!0}),i.copied++,i.bytes+=o.size}catch(e){i.failed.push({file:n,reason:e.message})}}return await a.flush(),i},digest:f,copy:u,walk:m,canFormat:p,Index:class{constructor(e){this.file=e,this.map=new Map,this.dirty=!1}async open(){try{const e=await t.promises.readFile(this.file,"utf8");for(const t of JSON.parse(e))this.map.set(t.digest,t)}catch(e){if("ENOENT"!==e.code)throw e}return this}has(e){const t=this.map.get(e);return!!t&&t.copies>=2&&t.verified}put(e,t){this.map.set(e,{digest:e,at:Date.now(),...t}),this.dirty=!0}frames(e){const t=[...this.map.values()];return e?t.filter((t=>t.card===e)):t}async flush(){if(!this.dirty)return 0;const e=[...this.map.values()];return await t.promises.writeFile(this.file,JSON.stringify(e)),this.dirty=!1,e.length}},retry:c};const d={arw:"raw",cr2:"raw",cr3:"raw",nef:"raw",orf:"raw",raf:"raw",rw2:"raw",dng:"raw",jpg:"jpeg",jpeg:"jpeg",tif:"tiff",tiff:"tiff",heic:"heif",xmp:"sidecar",aae:"sidecar",lrv:"proxy"},h={"SDXC-0001A7":{label:"sony tough 128",bytes:128e9,bus:"uhs-ii"},"SDXC-0002B3":{label:"sony tough 256",bytes:256e9,bus:"uhs-ii"},"CFEA-0007C1":{label:"cfexpress a 160",bytes:16e10,bus:"cfe-a"},"CFEA-0009D4":{label:"cfexpress a 320",bytes:32e10,bus:"cfe-a"},"SDXC-0011E8":{label:"angelbird v90",bytes:128e9,bus:"uhs-ii"}};function w(e){const t=r.extname(e).slice(1).toLowerCase();return d[t]||"other"}function y(e){return h[e]||{label:"unknown card",bytes:0,bus:"?"}}function b(e){const t=["b","kb","mb","gb","tb"];let r=0;for(;e>=1024&&r<t.length-1;)e/=1024,r++;return(r?e.toFixed(1):e)+t[r]}module.exports.kind=w,module.exports.bytes=b,module.exports.profile=y,module.exports.summarise=async function(e,t){const r=t.frames(e.serial),s=r.reduce(((e,t)=>(e[w(t.name)]=(e[w(t.name)]||0)+1,e)),{});return{card:y(e.serial).label,frames:r.length,size:b(r.reduce(((e,t)=>e+(t.size||0)),0)),types:s,safe:p(e,t)}};const e=[[0,14,"ultrawide"],[14,24,"wide"],[24,50,"normal"],[50,135,"short tele"],[135,400,"tele"],[400,1200,"long"]],t=()=>({frames:0,keepers:0,seconds:0,bodies:{},glass:{},bands:{},iso:[],hours:new Array(24).fill(0),months:new Array(12).fill(0),days:{}});function n(e,t,n=1){return t?(e[t]=(e[t]||0)+n,e):e}export function aggregate(r,o){return r.filter((e=>e.shot&&new Date(e.shot).getFullYear()===o)).reduce(((t,r)=>{const o=new Date(r.shot);return t.frames++,r.rating>=3&&t.keepers++,t.seconds+=r.shutter||0,n(t.bodies,r.body),n(t.glass,r.lens),n(t.bands,function(t){for(const[n,r,o]of e)if(t>=n&&t<r)return o;return"long"}(r.focal||0)),n(t.days,o.toISOString().slice(0,10)),r.iso&&t.iso.push(r.iso),t.hours[o.getHours()]++,t.months[o.getMonth()]++,t}),t())}export function top(e,t=3){return Object.entries(e).sort(((e,t)=>t[1]-e[1]||e[0].localeCompare(t[0]))).slice(0,t).map((([e,t])=>({name:e,count:t})))}export function median(e){if(!e.length)return 0;const t=[...e].sort(((e,t)=>e-t)),n=t.length>>1;return t.length%2?t[n]:(t[n-1]+t[n])/2}export function peak(e){const t=e.reduce(((t,n,r)=>n>e[t]?r:t),0);return{hour:t,label:(n=t,(n%12||12)+(n<12?"am":"pm")),frames:e[t]};var n}export function streak(e){const t=Object.keys(e).sort();let n=0,r=0,o=null;for(const e of t){const t=Date.parse(e)/864e5;r=null!=o&&t-o==1?r+1:1,r>n&&(n=r),o=t}return n}export function busiest(e,t=5){return top(e,t).map((({name:e,count:t})=>({date:e,frames:t,weekday:new Date(e).toLocaleDateString("en-CA",{weekday:"short"})})))}export function hours(e){const t=e/3600;return t<1?Math.round(e/60)+"m":t.toFixed(1)+"h"}export function wrapped(e,t=(new Date).getFullYear()){const n=aggregate(e,t);return n.frames?{year:t,frames:n.frames,keepers:n.keepers,hit:Math.round(n.keepers/n.frames*100)+"%",shutter:hours(n.seconds),bodies:top(n.bodies),glass:top(n.glass,5),reach:top(n.bands,6),iso:{median:median(n.iso),max:Math.max(...n.iso,0)},peak:peak(n.hours),streak:streak(n.days),busiest:busiest(n.days),cadence:n.months.map((e=>Math.round(e/n.frames*100)))}:null}export const MONTHS=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];export const NAMES={"ILCE-7RM5":"a7r v","ILCE-9M3":"a9 iii","ILCE-6700":"a6700","FE 200-600mm F5.6-6.3 G OSS":"200-600 g","FE 70-200mm F2.8 GM OSS II":"70-200 gm ii","FE 24-70mm F2.8 GM II":"24-70 gm ii","FE 14mm F1.8 GM":"14 gm","FE 90mm F2.8 Macro G OSS":"90 macro","FE 2.8/100 STF GM OSS":"100 stf"};export function label(e){return NAMES[e]||e}export function sparkline(e,t=12){const n="▁▂▃▄▅▆▇█".split(""),r=Math.max(...e,1);return e.slice(0,t).map((e=>n[Math.min(n.length-1,Math.round(e/r*(n.length-1)))])).join("")}export function cadence(e){return e.map(((e,t)=>({month:MONTHS[t],share:e,bar:sparkline([e])})))}export function sentences(e){if(!e)return[];const[t]=e.bodies,[n]=e.glass;return[e.frames+" frames in "+e.year,e.shutter+" with the shutter open",t?label(t.name)+" for "+t.count:null,n?label(n.name)+" on "+n.count:null,"most of it around "+e.peak.label,e.streak>1?e.streak+" days running":null].filter(Boolean)}export function card(e){return{lines:sentences(e),spark:sparkline(e?e.cadence:[]),reach:(e?e.reach:[]).map((e=>e.name+" "+e.count))}}