fluent-file 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { createReadStream, createWriteStream } from "node:fs";
2
2
  import { inspect } from "node:util";
3
- import * as fluent_command1 from "fluent-command";
3
+ import * as fluent_command0$1 from "fluent-command";
4
4
  import * as fluent_command0 from "fluent-command";
5
5
  import { WriteFileOptions } from "fs-extra/esm";
6
6
  import * as neverthrow0$1 from "neverthrow";
7
7
  import * as neverthrow0 from "neverthrow";
8
8
  import { ResultAsync } from "neverthrow";
9
9
  import sharpLib, { AvifOptions, ResizeOptions, SharpOptions } from "sharp";
10
- import * as zerde5 from "zerde";
11
10
  import * as zerde0 from "zerde";
11
+ import * as zerde1 from "zerde";
12
12
  import { ParseOptions, Prettify, StringifyOptions } from "zerde";
13
13
  import * as zod0 from "zod";
14
14
  import z from "zod";
@@ -226,7 +226,7 @@ declare function getVideoMetaData(path: string): neverthrow0$1.ResultAsync<{
226
226
  nb_frames: number;
227
227
  bit_rate: number;
228
228
  }[];
229
- }, zerde5.ParseError | zerde5.ValidationError | fluent_command1.FluentCommandError>;
229
+ }, fluent_command0$1.FluentCommandError | zerde0.ParseError | zerde0.ValidationError>;
230
230
  type ExtractFrameOptions = FileOutputOptions & {
231
231
  time?: number;
232
232
  unit?: "s" | "ms" | "us";
@@ -297,11 +297,11 @@ declare class FluentFile<Content = string, ParsedContent = Content> {
297
297
  remove: () => ResultAsync<void, FileRemoveError>;
298
298
  readText: (options?: FileReadOptions | undefined) => ResultAsync<string, FileReadError>;
299
299
  readBuffer: (options?: Pick<FileReadOptions, "flag" | "signal"> | undefined) => ResultAsync<Buffer<ArrayBufferLike>, FileReadError>;
300
- read: (options?: FileReadOptions) => ResultAsync<ParsedContent, FileReadError | zerde0.ParseError | zerde0.ValidationError>;
300
+ read: (options?: FileReadOptions) => ResultAsync<ParsedContent, FileReadError | zerde1.ParseError | zerde1.ValidationError>;
301
301
  createReadStream: (readStreamOptions?: Parameters<typeof createReadStream>[1]) => fs0.ReadStream;
302
302
  writeText: (textContent: string, writeOptions?: WriteFileOptions | undefined) => ResultAsync<void, FileWriteError>;
303
303
  writeBuffer: (bufferContent: Buffer<ArrayBufferLike>, writeOptions?: WriteFileOptions | undefined) => ResultAsync<void, FileWriteError>;
304
- write: (content: Content, options?: FileWriteOptions) => ResultAsync<void, FileWriteError | zerde0.ValidationError | zerde0.StringifyError>;
304
+ write: (content: Content, options?: FileWriteOptions) => ResultAsync<void, FileWriteError | zerde1.ValidationError | zerde1.StringifyError>;
305
305
  createWriteStream: (writeStreamOptions?: Parameters<typeof createWriteStream>[1]) => fs0.WriteStream;
306
306
  append: (data: string | Buffer<ArrayBufferLike>, writeOptions?: WriteFileOptions | undefined) => ResultAsync<void, FileAppendError>;
307
307
  image: (sharpOptions?: SharpOptions) => {
@@ -471,7 +471,7 @@ declare class FluentFile<Content = string, ParsedContent = Content> {
471
471
  nb_frames: number;
472
472
  bit_rate: number;
473
473
  }[];
474
- }, zerde0.ParseError | zerde0.ValidationError | fluent_command0.FluentCommandError>;
474
+ }, fluent_command0.FluentCommandError | zerde1.ParseError | zerde1.ValidationError>;
475
475
  extractFrame: (extractFrameOptions?: ExtractFrameOptions) => Promise<neverthrow0.Result<FluentFile<string, string>, fluent_command0.FluentCommandError>>;
476
476
  };
477
477
  download: (url: string, downloadOptions?: DownloadFileOptions) => ResultAsync<"ALREADY_EXISTS" | "SUCCESS", FileDownloadError>;
@@ -491,4 +491,13 @@ type FileWriteOptions = StringifyOptions & Partial<{
491
491
  declare function ffile(file: PathPieces[number], ...extraPathPieces: PathPieces): FluentFile<string, string>;
492
492
  declare function homeFile(file: PathPieces[number], ...extraPathPieces: PathPieces): FluentFile<string, string>;
493
493
  //#endregion
494
- export { DEFAULT_PHASH_THRESHOLD, DESTINATION_FALLBACK, ExtractFrameOptions, FileAppendError, FileChmodError, FileCopyError, FileDownloadError, FileImageConvertError, FileImageMetadataError, FileImagePhashError, FileImageResizeError, FileLinkError, FileMoveError, FileOperation, FileReadError, FileReadOptions, FileRemoveError, FileStatError, FileSymLinkError, FileWriteError, FileWriteOptions, FindFilesGlobOptions, FindFoldersGlobOptions, FluentFile, FluentFolder, FsFlag, FsFlags, IMAGE_EXTENSIONS, ImageResizeOptions, MAX_DIFFERENCES, PhashSimilarity, PhashSimilarityInfo, PhashString, PhashThreshold, ToAVIFOptions, VIDEO_EXTENSIONS, binaryStringRegex, comparePhashes, ffile, folder, getVideoMetaData, homeFile, phashStringSchema, phashThresholdSchema, phashesMatch };
494
+ //#region src/folder/xdg.d.ts
495
+ declare function cacheFolder(...pathPieces: PathPieces): FluentFolder;
496
+ declare function configFolder(...pathPieces: PathPieces): FluentFolder;
497
+ declare function dataFolder(...pathPieces: PathPieces): FluentFolder;
498
+ declare function logsFolder(...pathPieces: PathPieces): FluentFolder;
499
+ declare function homeFolder(...pathPieces: PathPieces): FluentFolder;
500
+ declare function tempFolder(...pathPieces: PathPieces): FluentFolder;
501
+ declare function currentFolder(): FluentFolder;
502
+ //#endregion
503
+ export { DEFAULT_PHASH_THRESHOLD, DESTINATION_FALLBACK, ExtractFrameOptions, FileAppendError, FileChmodError, FileCopyError, FileDownloadError, FileImageConvertError, FileImageMetadataError, FileImagePhashError, FileImageResizeError, FileLinkError, FileMoveError, FileOperation, FileReadError, FileReadOptions, FileRemoveError, FileStatError, FileSymLinkError, FileWriteError, FileWriteOptions, FindFilesGlobOptions, FindFoldersGlobOptions, FluentFile, FluentFolder, FsFlag, FsFlags, IMAGE_EXTENSIONS, ImageResizeOptions, MAX_DIFFERENCES, PhashSimilarity, PhashSimilarityInfo, PhashString, PhashThreshold, ToAVIFOptions, VIDEO_EXTENSIONS, binaryStringRegex, cacheFolder, comparePhashes, configFolder, currentFolder, dataFolder, ffile, folder, getVideoMetaData, homeFile, homeFolder, logsFolder, phashStringSchema, phashThresholdSchema, phashesMatch, tempFolder };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{constants as e,createReadStream as t,createWriteStream as n}from"node:fs";import{chmod as r,copyFile as i,opendir as a,readFile as o,stat as s}from"node:fs/promises";import{homedir as c,platform as l}from"node:os";import{inspect as u}from"node:util";import{fcmd as d}from"fluent-command";import{appendFile as f}from"fs-extra";import{emptyDir as ee,ensureDir as te,ensureFile as ne,ensureLink as re,ensureSymlink as ie,move as ae,outputFile as p,remove as m}from"fs-extra/esm";import{ResultAsync as h}from"neverthrow";import g,{basename as oe}from"pathe";import se from"sharp";import ce from"sharp-phash";import{parseString as le,zparse as _,zstringify as ue}from"zerde";import v from"zod";import y from"picomatch";import{pipeline as b}from"node:stream/promises";const de={Append:`a`,AppendOrFail:`ax`,AppendAndRead:`a+`,AppendAndReadOrFail:`ax+`,Read:`r`,ReadAndWrite:`r+`,Write:`w`,WriteOrFailIfExists:`wx`};function x(...e){let t=e.map((e,t)=>{if(typeof e==`number`)return e.toString();if(t===0&&e===`~`)return c();if(e.toUpperCase()!==e)return e;let n=``;if(e.startsWith(`$`)&&(n=e.slice(1)),l()===`win32`&&e.startsWith(`%`)&&e.endsWith(`%`)&&(n=e.slice(1,-1)),n!==``){let t=process.env[n];if(!t)throw Error(`Missing Environment variable ${e}`);return t}return e});return g.resolve(...t)}function S(e){let t=e.lastIndexOf(`.`);return t<0?e:e.slice(t+1)}function fe(e){return S(g.extname(e))}const pe=4,me=-5;var C=class extends Error{operation;path;constructor(e,t){super(),this.path=e,this.operation=this.constructor.name.slice(pe,me),this.message=`Error trying to ${this.operation} file: ${e}`,this.cause=t,this.name=this.constructor.name}},w=class extends C{url;constructor(e,t,n){super(e,n),this.url=t,this.message=`Error trying to download url: ${t} to file: ${e}`}},he=class extends C{},ge=class extends C{},T=class extends C{},E=class extends C{},D=class extends C{},O=class extends C{},k=class extends C{},A=class extends C{},j=class extends C{},M=class extends C{};const N=`DESTINATION_FALLBACK`;var P=class extends C{destinationPath;constructor(e,t,n){super(e,n),this.destinationPath=t??N}},F=class extends P{},I=class extends P{},L=class extends P{},R=class extends P{};const _e=6,ve=[`avif`,`gif`,`jpeg`,`jpg`,`png`,`svg`,`tiff`,`webp`],z=64,ye=16,B=/^[01]+$/,V=v.codec(v.string().regex(B).length(z),v.hex().brand(`PhashString`),{decode:e=>BigInt(`0b${e}`).toString(ye),encode:e=>BigInt(`0x${e}`).toString(2).padStart(z,`0`)}),H=v.int().nonnegative().max(z).brand(`PhashThreshold`),be=6,U=H.parse(be);function xe(e,t,n=U){if(e===t)return Object.freeze({level:`SAME`,diff:0});let r=V.encode(e),i=V.encode(t),a=0,o=z;for(;o--;)r[o]!==i[o]&&a++;let s=a<n?`SIMILAR`:`DIFFERENT`;return Object.freeze({level:s,diff:a})}function Se(e,t,n=U){if(e===t)return!0;let r=V.encode(e),i=V.encode(t),a=0,o=z;for(;o--;)if(r[o]!==i[o]&&a++,a>=n)return!1;return!0}const Ce=v.coerce.number().positive(),W=v.coerce.number().int(),we=W.nonnegative(),G=W.positive(),K=v.object({duration:Ce,bit_rate:G}),Te=1e3;function q(e){let t=Math.round(e*Te),n=Math.trunc(e%60),r=Math.trunc(e/60%60),i=Math.trunc(e/60/60%60),a=[i,r,n].filter((e,t)=>t>0||e>0).map((e,t)=>{let n=e.toString();return t>0&&(n=n.padStart(2,`0`)),n}).join(`:`);return{millis:t,seconds:n,minutes:r,hours:i,hms:a}}const J=v.object({...K.shape,codec_name:v.string(),codec_long_name:v.string(),codec_tag_string:v.string(),nb_frames:G}),Ee=v.object({...J.shape,codec_type:v.literal(`audio`),channels:G,channel_layout:v.string()}),De=v.object({...J.shape,codec_type:v.literal(`video`),height:G,width:G}),Oe=v.object({...K.shape,nb_streams:G,format_name:v.string(),format_long_name:v.string(),size:G}),ke=v.object({format:Oe,streams:v.array(v.union([Ee,De])).min(2)}).transform(({format:{duration:e,...t},streams:n},{addIssue:r})=>{let i=n.filter(e=>e.codec_type===`video`).map(({duration:e,...t})=>({...t,...q(e)})).at(0);if(!i)return r({code:`custom`,message:`Video was missing video stream`}),v.NEVER;let a=n.filter(e=>e.codec_type===`audio`).map(({duration:e,...t})=>({...t,...q(e)}));return a.length===0?(r({code:`custom`,message:`Video was missing audio stream`}),v.NEVER):{videoStream:i,audioStreams:a,...t,...q(e)}}),Ae=[`avi`,`flv`,`mkv`,`mov`,`mp4`,`mpeg`,`mpg`,`rm`,`rmvb`,`webm`,`wmv`];function Y(e){return d(`ffprobe`).opt(`hide_banner`).opt(`show_format`).opt(`show_streams`).opt({v:`error`,print_format:`json`}).args(e).read().andThen(e=>_(e.stdout,ke,`json`))}var X=class extends Error{operation;path;constructor(e,t,n){let r=`Error trying to ${e} folder: ${t}`;super(r,{cause:n}),this.path=t,this.operation=e,this.name=this.constructor.name}},je=class extends X{constructor(e,t){super(`glob`,e,t)}};function Me(){return Q(process.cwd())}var Z=class{path;name;constructor(...e){this.path=x(...e),this.name=oe(this.path),this.name||=this.path}get info(){return{path:this.path,name:this.name}}folder=(...e)=>Q(this.path,...e);file=(e,...t)=>$(this.path,e,...t);relativePath=(e=Me())=>{let t=this.path;return t.startsWith(e.path)&&(t=t.slice(e.path.length),t.startsWith(`/`))?t.slice(1):t};toString=()=>this.path;toJSON=()=>({FluentFolder:this.info});[u.custom]=()=>this.toJSON();stats=h.fromThrowable(async()=>{let e=await s(this.path);if(!e.isDirectory())throw new X(`stat`,this.path,`FolderWasNotFolder`);return e},e=>e instanceof X?e:new X(`stat`,this.path,e));exists=async()=>(await this.stats()).isOk();ensureExists=()=>te(this.path);ensureEmpty=()=>ee(this.path);remove=()=>m(this.path);findFolders=h.fromThrowable(async(e={})=>{let t=e.glob?y(e.glob,{cwd:this.path}):null,n=await a(this.path,{recursive:e.recursive??!0}),r=[];for await(let e of n){if(!e.isDirectory())continue;let n=g.resolve(e.parentPath,e.name);if(t&&!t(n))continue;r.push(n)}return r.sort().map(e=>Q(e))},e=>new je(this.path,e));findFiles=h.fromThrowable(async(e={})=>{let t=e.glob?y(e.glob,{cwd:this.path}):null,n=await a(this.path,{recursive:e.recursive??!0}),r=[],i=(e.exts??[]).map(S);for await(let e of n){if(!e.isFile())continue;let n=g.resolve(e.parentPath,e.name);if(i.length>0){let t=fe(e.name);if(!i.includes(t))continue}if(t&&!t(n))continue;r.push(n)}return r.sort().map(e=>$(e))},e=>new je(this.path,e))};function Q(...e){return new Z(...e)}const Ne=h.fromThrowable(async(e,t,n={})=>{try{let{overwrite:r=!1,progressThrottle:i=100,onProgress:a}=n;if(!r&&await t.exists())return`ALREADY_EXISTS`;await t.folder().ensureExists();let o=await fetch(e);if(!o.ok){let{status:t,statusText:n,redirected:r,type:i}=o,a={};throw o.headers.forEach((e,t)=>{a[t]=e}),Error(`Got ${o.status} ${o.statusText} for url: ${e}`,{cause:{status:t,statusText:n,headers:a,redirected:r,type:i}})}let s=G.parse(o.headers.get(`content-length`));if(!o.body)throw Error(`Request body was null for url: ${e}`,{cause:o});let c=o.body,l=t.createWriteStream();if(!a)return await b(c,l),`SUCCESS`;let u=0,d=null,f=e=>{u+=e,!d&&(a({downloadedBytes:u,totalBytes:s}),d=setTimeout(()=>{d=null},i))};return await b(c,async function*(e){for await(let t of e)f(t.length)},l),`SUCCESS`}catch(n){throw new w(t.path(),e,n)}},e=>e);var Pe=class a{#path;#folderPath;#name;#basename;#ext;#schema;#info;#ensureDestination=async e=>{let t=e instanceof a?e:e.file(this.#name);return await t.folder().ensureExists(),await t.remove(),t.path()};#prepareTarget=async e=>{let{newFolder:t=this.folder(),newBaseName:n=this.#basename,newExt:r=this.#ext}=e,i=t.file(`${n}.${r}`);return await i.remove(),await t.ensureExists(),i};constructor(e,t,...n){this.#path=x(t,...n),this.#schema=e;let r=Fe(this.#path);this.#folderPath=r.folderPath,this.#name=r.name,this.#basename=r.basename,this.#ext=r.ext,this.#info=r}toString=()=>this.#path;toJSON=()=>({FluentFile:this.info});[u.custom]=()=>this.toJSON();path=()=>this.#path;folderPath=()=>this.#folderPath;name(e){return e===void 0?this.#name:(this.#name=e,this.#path=`${this.#folderPath}/${e}`,this)}basename(e){return e===void 0?this.#basename:(this.#basename=e,this.#name=e+this.#ext,this.#path=`${this.#folderPath}/${this.#name}`,this)}ext(e){return e===void 0?this.#ext:(this.#ext=e,this.#name=this.#basename+e,this.#path=`${this.#folderPath}/${this.#name}`,this)}schema=e=>new a(e,this.#path);get info(){return this.#info}relativePath=(e=Me())=>{let t=this.#path;return t.startsWith(e.path)&&(t=t.slice(e.path.length),t.startsWith(`/`))?t.slice(1):t};file=(e,...t)=>new a(this.#schema,this.#folderPath,e,...t);folder=(...e)=>new Z(this.#folderPath,...e);stats=h.fromThrowable(async()=>{let e=await s(this.#path);if(!e.isFile())throw new j(this.#path,`FileWasNotFile`);return e},e=>e instanceof j?e:new j(this.#path,e));exists=async()=>(await this.stats()).isOk();ensureExists=()=>ne(this.#path);chmod=h.fromThrowable(async e=>{await r(this.#path,e)},e=>new ge(this.#path,e));copyTo=h.fromThrowable(async t=>{let n=null;try{n=await this.#ensureDestination(t),await i(this.#path,n,e.COPYFILE_FICLONE)}catch(e){throw new F(this.#path,n,e)}},e=>e);moveTo=h.fromThrowable(async(e,t)=>{let n=null;try{n=await this.#ensureDestination(e),await ae(this.#path,n,{overwrite:!0,dereference:t})}catch(e){throw new I(this.#path,n,e)}},e=>e);linkTo=h.fromThrowable(async e=>{let t=null;try{t=await this.#ensureDestination(e),await re(this.#path,t)}catch(e){throw new L(this.#path,t,e)}},e=>e);symlinkTo=h.fromThrowable(async e=>{let t=null;try{t=await this.#ensureDestination(e),await ie(this.#path,t)}catch(e){throw new R(this.#path,t,e)}},e=>e);remove=h.fromThrowable(()=>m(this.#path),e=>new A(this.#path,e));readText=h.fromThrowable((e={})=>o(this.#path,{encoding:`utf8`,...e}),e=>new k(this.#path,e));readBuffer=h.fromThrowable((e={})=>o(this.#path,e),e=>new k(this.#path,e));read=(e={})=>this.readText(e).andThen(t=>_(t,this.#schema,{format:this.#path,...e}));createReadStream=e=>t(this.#path,e);writeText=h.fromThrowable((e,t={})=>p(this.#path,e,t),e=>new M(this.#path,e));writeBuffer=h.fromThrowable((e,t={})=>p(this.#path,e,t),e=>new M(this.#path,e));write=(e,t={})=>ue(e,this.#schema,t).andThen(e=>this.writeText(e,t));createWriteStream=e=>n(this.#path,e);append=h.fromThrowable((e,t={})=>f(this.#path,e,t),e=>new he(this.#path,e));image=(e={})=>{let t=se(this.#path,e),n=h.fromThrowable(()=>t.metadata(),e=>new E(this.#path,e)),r=h.fromThrowable(async e=>{let n=await this.#prepareTarget(e);return await t.resize(e).toFile(n.path()),n},e=>new O(this.#path,e)),i=h.fromThrowable(async(e={})=>{let n=await this.#prepareTarget({...e,newExt:`avif`});return await t.resize(e).avif(e).toFile(n.path()),n},e=>new T(this.#path,e)),a=h.fromThrowable(async()=>{let t=await ce(this.#path,e);return V.decode(t)},e=>new D(this.#path,e));return{...t,metadata:n,resize:r,toAVIF:i,phash:a}};video=()=>({metadata:()=>Y(this.#path),extractFrame:async(e={})=>{let{time:t=1,unit:n=`s`,ext:r=`png`,...i}=e,a=n===`s`?t:`${t}${n}`,o=await this.#prepareTarget({newExt:r,...i});return d(`ffmpeg`).opt(`hide_banner`).opt({ss:a,i:this.#path,"frames:v":1,y:``}).args(o.path()).read().map(()=>o)}});download=(e,t={})=>Ne(e,this,t)};function Fe(e){let t=g.basename(e),n=g.dirname(e),r=``,i=``,a=t.lastIndexOf(`.`);return a<=0?(r=t,i=``):(r=t.slice(0,a),i=t.slice(a+1)),{absolutePath:e,folderPath:n,name:t,basename:r,ext:i}}function $(e,...t){return new Pe(le(),e,...t)}function Ie(e,...t){return $(c(),e,...t)}export{U as DEFAULT_PHASH_THRESHOLD,N as DESTINATION_FALLBACK,he as FileAppendError,ge as FileChmodError,F as FileCopyError,w as FileDownloadError,T as FileImageConvertError,E as FileImageMetadataError,D as FileImagePhashError,O as FileImageResizeError,L as FileLinkError,I as FileMoveError,k as FileReadError,A as FileRemoveError,j as FileStatError,R as FileSymLinkError,M as FileWriteError,Pe as FluentFile,Z as FluentFolder,de as FsFlags,ve as IMAGE_EXTENSIONS,_e as MAX_DIFFERENCES,Ae as VIDEO_EXTENSIONS,B as binaryStringRegex,xe as comparePhashes,$ as ffile,Q as folder,Y as getVideoMetaData,Ie as homeFile,V as phashStringSchema,H as phashThresholdSchema,Se as phashesMatch};
1
+ import{constants as e,createReadStream as t,createWriteStream as n}from"node:fs";import{chmod as r,copyFile as i,opendir as a,readFile as o,stat as s}from"node:fs/promises";import{homedir as c,platform as l,tmpdir as u}from"node:os";import{inspect as d}from"node:util";import{fcmd as f}from"fluent-command";import{appendFile as ee}from"fs-extra";import{emptyDir as te,ensureDir as ne,ensureFile as re,ensureLink as ie,ensureSymlink as ae,move as oe,outputFile as p,remove as m}from"fs-extra/esm";import{ResultAsync as h}from"neverthrow";import g,{basename as se}from"pathe";import ce from"sharp";import le from"sharp-phash";import{parseString as ue,zparse as de,zstringify as fe}from"zerde";import _ from"zod";import pe from"picomatch";import{pipeline as me}from"node:stream/promises";const he={Append:`a`,AppendOrFail:`ax`,AppendAndRead:`a+`,AppendAndReadOrFail:`ax+`,Read:`r`,ReadAndWrite:`r+`,Write:`w`,WriteOrFailIfExists:`wx`};function v(...e){let t=e.map((e,t)=>{if(typeof e==`number`)return e.toString();if(t===0&&e===`~`)return c();if(e.toUpperCase()!==e)return e;let n=``;if(e.startsWith(`$`)&&(n=e.slice(1)),l()===`win32`&&e.startsWith(`%`)&&e.endsWith(`%`)&&(n=e.slice(1,-1)),n!==``){let t=process.env[n];if(!t)throw Error(`Missing Environment variable ${e}`);return t}return e});return g.resolve(...t)}function y(e){let t=e.lastIndexOf(`.`);return t<0?e:e.slice(t+1)}function ge(e){return y(g.extname(e))}const _e=4,ve=-5;var b=class extends Error{operation;path;constructor(e,t){super(),this.path=e,this.operation=this.constructor.name.slice(_e,ve),this.message=`Error trying to ${this.operation} file: ${e}`,this.cause=t,this.name=this.constructor.name}},x=class extends b{url;constructor(e,t,n){super(e,n),this.url=t,this.message=`Error trying to download url: ${t} to file: ${e}`}},S=class extends b{},C=class extends b{},w=class extends b{},T=class extends b{},E=class extends b{},D=class extends b{},O=class extends b{},k=class extends b{},A=class extends b{},j=class extends b{};const M=`DESTINATION_FALLBACK`;var N=class extends b{destinationPath;constructor(e,t,n){super(e,n),this.destinationPath=t??M}},P=class extends N{},F=class extends N{},I=class extends N{},L=class extends N{};const ye=6,be=[`avif`,`gif`,`jpeg`,`jpg`,`png`,`svg`,`tiff`,`webp`],R=64,xe=16,z=/^[01]+$/,B=_.codec(_.string().regex(z).length(R),_.hex().brand(`PhashString`),{decode:e=>BigInt(`0b${e}`).toString(xe),encode:e=>BigInt(`0x${e}`).toString(2).padStart(R,`0`)}),V=_.int().nonnegative().max(R).brand(`PhashThreshold`),Se=6,H=V.parse(Se);function Ce(e,t,n=H){if(e===t)return Object.freeze({level:`SAME`,diff:0});let r=B.encode(e),i=B.encode(t),a=0,o=R;for(;o--;)r[o]!==i[o]&&a++;let s=a<n?`SIMILAR`:`DIFFERENT`;return Object.freeze({level:s,diff:a})}function we(e,t,n=H){if(e===t)return!0;let r=B.encode(e),i=B.encode(t),a=0,o=R;for(;o--;)if(r[o]!==i[o]&&a++,a>=n)return!1;return!0}const Te=_.coerce.number().positive(),U=_.coerce.number().int(),Ee=U.nonnegative(),W=U.positive(),G=_.object({duration:Te,bit_rate:W}),De=1e3;function K(e){let t=Math.round(e*De),n=Math.trunc(e%60),r=Math.trunc(e/60%60),i=Math.trunc(e/60/60%60),a=[i,r,n].filter((e,t)=>t>0||e>0).map((e,t)=>{let n=e.toString();return t>0&&(n=n.padStart(2,`0`)),n}).join(`:`);return{millis:t,seconds:n,minutes:r,hours:i,hms:a}}const q=_.object({...G.shape,codec_name:_.string(),codec_long_name:_.string(),codec_tag_string:_.string(),nb_frames:W}),Oe=_.object({...q.shape,codec_type:_.literal(`audio`),channels:W,channel_layout:_.string()}),ke=_.object({...q.shape,codec_type:_.literal(`video`),height:W,width:W}),Ae=_.object({...G.shape,nb_streams:W,format_name:_.string(),format_long_name:_.string(),size:W}),je=_.object({format:Ae,streams:_.array(_.union([Oe,ke])).min(2)}).transform(({format:{duration:e,...t},streams:n},{addIssue:r})=>{let i=n.filter(e=>e.codec_type===`video`).map(({duration:e,...t})=>({...t,...K(e)})).at(0);if(!i)return r({code:`custom`,message:`Video was missing video stream`}),_.NEVER;let a=n.filter(e=>e.codec_type===`audio`).map(({duration:e,...t})=>({...t,...K(e)}));return a.length===0?(r({code:`custom`,message:`Video was missing audio stream`}),_.NEVER):{videoStream:i,audioStreams:a,...t,...K(e)}}),Me=[`avi`,`flv`,`mkv`,`mov`,`mp4`,`mpeg`,`mpg`,`rm`,`rmvb`,`webm`,`wmv`];function Ne(e){return f(`ffprobe`).opt(`hide_banner`).opt(`show_format`).opt(`show_streams`).opt({v:`error`,print_format:`json`}).args(e).read().andThen(e=>de(e.stdout,je,`json`))}var J=class extends Error{operation;path;constructor(e,t,n){let r=`Error trying to ${e} folder: ${t}`;super(r,{cause:n}),this.path=t,this.operation=e,this.name=this.constructor.name}},Pe=class extends J{constructor(e,t){super(`glob`,e,t)}};const Fe={CACHE:{darwin:[`~`,`Library`,`Caches`],linux:[`~`,`.cache`],win32:[`$LOCALAPPDATA`]},CONFIG:{darwin:[`~`,`Library`,`Preferences`],linux:[`~`,`.config`],win32:[`$APPDATA`]},DATA:{darwin:[`~`,`Library`,`Application Support`],linux:[`~`,`.local`,`share`],win32:[`$LOCALAPPDATA`]},STATE:{darwin:[`~`,`Library`,`Logs`],linux:[`~`,`.local`,`state`],win32:[`$LOCALAPPDATA`]}};function Y(e){let t=l();if(t===`win32`||t===`darwin`)return Fe[e][t];let n=process.env[`XDG_${e}_HOME`];return n?[n]:Fe[e].linux}function Ie(...e){return Q(...Y(`CACHE`),...e)}function Le(...e){return Q(...Y(`CONFIG`),...e)}function Re(...e){return Q(...Y(`DATA`),...e)}function ze(...e){return Q(...Y(`STATE`),...e)}function Be(...e){return Q(c(),...e)}function Ve(...e){return Q(u(),...e)}function X(){return Q(process.cwd())}var Z=class{path;name;constructor(...e){this.path=v(...e),this.name=se(this.path),this.name||=this.path}get info(){return{path:this.path,name:this.name}}folder=(...e)=>Q(this.path,...e);file=(e,...t)=>$(this.path,e,...t);relativePath=(e=X())=>{let t=this.path;return t.startsWith(e.path)&&(t=t.slice(e.path.length),t.startsWith(`/`))?t.slice(1):t};toString=()=>this.path;toJSON=()=>({FluentFolder:this.info});[d.custom]=()=>this.toJSON();stats=h.fromThrowable(async()=>{let e=await s(this.path);if(!e.isDirectory())throw new J(`stat`,this.path,`FolderWasNotFolder`);return e},e=>e instanceof J?e:new J(`stat`,this.path,e));exists=async()=>(await this.stats()).isOk();ensureExists=()=>ne(this.path);ensureEmpty=()=>te(this.path);remove=()=>m(this.path);findFolders=h.fromThrowable(async(e={})=>{let t=e.glob?pe(e.glob,{cwd:this.path}):null,n=await a(this.path,{recursive:e.recursive??!0}),r=[];for await(let e of n){if(!e.isDirectory())continue;let n=g.resolve(e.parentPath,e.name);if(t&&!t(n))continue;r.push(n)}return r.sort().map(e=>Q(e))},e=>new Pe(this.path,e));findFiles=h.fromThrowable(async(e={})=>{let t=e.glob?pe(e.glob,{cwd:this.path}):null,n=await a(this.path,{recursive:e.recursive??!0}),r=[],i=(e.exts??[]).map(y);for await(let e of n){if(!e.isFile())continue;let n=g.resolve(e.parentPath,e.name);if(i.length>0){let t=ge(e.name);if(!i.includes(t))continue}if(t&&!t(n))continue;r.push(n)}return r.sort().map(e=>$(e))},e=>new Pe(this.path,e))};function Q(...e){return new Z(...e)}const He=h.fromThrowable(async(e,t,n={})=>{try{let{overwrite:r=!1,progressThrottle:i=100,onProgress:a}=n;if(!r&&await t.exists())return`ALREADY_EXISTS`;await t.folder().ensureExists();let o=await fetch(e);if(!o.ok){let{status:t,statusText:n,redirected:r,type:i}=o,a={};throw o.headers.forEach((e,t)=>{a[t]=e}),Error(`Got ${o.status} ${o.statusText} for url: ${e}`,{cause:{status:t,statusText:n,headers:a,redirected:r,type:i}})}let s=W.parse(o.headers.get(`content-length`));if(!o.body)throw Error(`Request body was null for url: ${e}`,{cause:o});let c=o.body,l=t.createWriteStream();if(!a)return await me(c,l),`SUCCESS`;let u=0,d=null,f=e=>{u+=e,!d&&(a({downloadedBytes:u,totalBytes:s}),d=setTimeout(()=>{d=null},i))};return await me(c,async function*(e){for await(let t of e)f(t.length)},l),`SUCCESS`}catch(n){throw new x(t.path(),e,n)}},e=>e);var Ue=class a{#path;#folderPath;#name;#basename;#ext;#schema;#info;#ensureDestination=async e=>{let t=e instanceof a?e:e.file(this.#name);return await t.folder().ensureExists(),await t.remove(),t.path()};#prepareTarget=async e=>{let{newFolder:t=this.folder(),newBaseName:n=this.#basename,newExt:r=this.#ext}=e,i=t.file(`${n}.${r}`);return await i.remove(),await t.ensureExists(),i};constructor(e,t,...n){this.#path=v(t,...n),this.#schema=e;let r=We(this.#path);this.#folderPath=r.folderPath,this.#name=r.name,this.#basename=r.basename,this.#ext=r.ext,this.#info=r}toString=()=>this.#path;toJSON=()=>({FluentFile:this.info});[d.custom]=()=>this.toJSON();path=()=>this.#path;folderPath=()=>this.#folderPath;name(e){return e===void 0?this.#name:(this.#name=e,this.#path=`${this.#folderPath}/${e}`,this)}basename(e){return e===void 0?this.#basename:(this.#basename=e,this.#name=e+this.#ext,this.#path=`${this.#folderPath}/${this.#name}`,this)}ext(e){return e===void 0?this.#ext:(this.#ext=e,this.#name=this.#basename+e,this.#path=`${this.#folderPath}/${this.#name}`,this)}schema=e=>new a(e,this.#path);get info(){return this.#info}relativePath=(e=X())=>{let t=this.#path;return t.startsWith(e.path)&&(t=t.slice(e.path.length),t.startsWith(`/`))?t.slice(1):t};file=(e,...t)=>new a(this.#schema,this.#folderPath,e,...t);folder=(...e)=>new Z(this.#folderPath,...e);stats=h.fromThrowable(async()=>{let e=await s(this.#path);if(!e.isFile())throw new A(this.#path,`FileWasNotFile`);return e},e=>e instanceof A?e:new A(this.#path,e));exists=async()=>(await this.stats()).isOk();ensureExists=()=>re(this.#path);chmod=h.fromThrowable(async e=>{await r(this.#path,e)},e=>new C(this.#path,e));copyTo=h.fromThrowable(async t=>{let n=null;try{n=await this.#ensureDestination(t),await i(this.#path,n,e.COPYFILE_FICLONE)}catch(e){throw new P(this.#path,n,e)}},e=>e);moveTo=h.fromThrowable(async(e,t)=>{let n=null;try{n=await this.#ensureDestination(e),await oe(this.#path,n,{overwrite:!0,dereference:t})}catch(e){throw new F(this.#path,n,e)}},e=>e);linkTo=h.fromThrowable(async e=>{let t=null;try{t=await this.#ensureDestination(e),await ie(this.#path,t)}catch(e){throw new I(this.#path,t,e)}},e=>e);symlinkTo=h.fromThrowable(async e=>{let t=null;try{t=await this.#ensureDestination(e),await ae(this.#path,t)}catch(e){throw new L(this.#path,t,e)}},e=>e);remove=h.fromThrowable(()=>m(this.#path),e=>new k(this.#path,e));readText=h.fromThrowable((e={})=>o(this.#path,{encoding:`utf8`,...e}),e=>new O(this.#path,e));readBuffer=h.fromThrowable((e={})=>o(this.#path,e),e=>new O(this.#path,e));read=(e={})=>this.readText(e).andThen(t=>de(t,this.#schema,{format:this.#path,...e}));createReadStream=e=>t(this.#path,e);writeText=h.fromThrowable((e,t={})=>p(this.#path,e,t),e=>new j(this.#path,e));writeBuffer=h.fromThrowable((e,t={})=>p(this.#path,e,t),e=>new j(this.#path,e));write=(e,t={})=>fe(e,this.#schema,t).andThen(e=>this.writeText(e,t));createWriteStream=e=>n(this.#path,e);append=h.fromThrowable((e,t={})=>ee(this.#path,e,t),e=>new S(this.#path,e));image=(e={})=>{let t=ce(this.#path,e),n=h.fromThrowable(()=>t.metadata(),e=>new T(this.#path,e)),r=h.fromThrowable(async e=>{let n=await this.#prepareTarget(e);return await t.resize(e).toFile(n.path()),n},e=>new D(this.#path,e)),i=h.fromThrowable(async(e={})=>{let n=await this.#prepareTarget({...e,newExt:`avif`});return await t.resize(e).avif(e).toFile(n.path()),n},e=>new w(this.#path,e)),a=h.fromThrowable(async()=>{let t=await le(this.#path,e);return B.decode(t)},e=>new E(this.#path,e));return{...t,metadata:n,resize:r,toAVIF:i,phash:a}};video=()=>({metadata:()=>Ne(this.#path),extractFrame:async(e={})=>{let{time:t=1,unit:n=`s`,ext:r=`png`,...i}=e,a=n===`s`?t:`${t}${n}`,o=await this.#prepareTarget({newExt:r,...i});return f(`ffmpeg`).opt(`hide_banner`).opt({ss:a,i:this.#path,"frames:v":1,y:``}).args(o.path()).read().map(()=>o)}});download=(e,t={})=>He(e,this,t)};function We(e){let t=g.basename(e),n=g.dirname(e),r=``,i=``,a=t.lastIndexOf(`.`);return a<=0?(r=t,i=``):(r=t.slice(0,a),i=t.slice(a+1)),{absolutePath:e,folderPath:n,name:t,basename:r,ext:i}}function $(e,...t){return new Ue(ue(),e,...t)}function Ge(e,...t){return $(c(),e,...t)}export{H as DEFAULT_PHASH_THRESHOLD,M as DESTINATION_FALLBACK,S as FileAppendError,C as FileChmodError,P as FileCopyError,x as FileDownloadError,w as FileImageConvertError,T as FileImageMetadataError,E as FileImagePhashError,D as FileImageResizeError,I as FileLinkError,F as FileMoveError,O as FileReadError,k as FileRemoveError,A as FileStatError,L as FileSymLinkError,j as FileWriteError,Ue as FluentFile,Z as FluentFolder,he as FsFlags,be as IMAGE_EXTENSIONS,ye as MAX_DIFFERENCES,Me as VIDEO_EXTENSIONS,z as binaryStringRegex,Ie as cacheFolder,Ce as comparePhashes,Le as configFolder,X as currentFolder,Re as dataFolder,$ as ffile,Q as folder,Ne as getVideoMetaData,Ge as homeFile,Be as homeFolder,ze as logsFolder,B as phashStringSchema,V as phashThresholdSchema,we as phashesMatch,Ve as tempFolder};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluent-file",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "A fluent TypeScript library for working with files and folders",
5
5
  "keywords": [
6
6
  "files",