Add StartOS 0.4.0 packaging
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# User data (never bake personal data into the image)
|
||||
history/
|
||||
config/
|
||||
cookies.txt
|
||||
.env
|
||||
|
||||
# Build artifacts
|
||||
*.s9pk
|
||||
image.tar
|
||||
javascript/
|
||||
|
||||
# macOS artifacts
|
||||
.DS_Store
|
||||
*.command
|
||||
|
||||
# Local dev files (not needed in container)
|
||||
GET-STARTED.*
|
||||
build-guide-pdf.py
|
||||
create-app.sh
|
||||
setup.sh
|
||||
Start Summarizer.command
|
||||
YouTube Summarizer.app/
|
||||
|
||||
# StartOS packaging files (not part of the app image)
|
||||
startos/
|
||||
start9/
|
||||
s9pk.mk
|
||||
Makefile
|
||||
package.json
|
||||
package-lock.json
|
||||
tsconfig.json
|
||||
icon.png
|
||||
icon.svg
|
||||
LICENSE
|
||||
CONTRIBUTING.md
|
||||
README.md
|
||||
|
||||
# Game plan / docs
|
||||
START9_PACKAGING_GAMEPLAN.md
|
||||
assets/ABOUT.md
|
||||
|
||||
# Git
|
||||
.git/
|
||||
.github/
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
# ─────────────────────────────────────────────────────────
|
||||
# YouTube Summarizer — StartOS 0.4 Docker image
|
||||
#
|
||||
# Includes: Node.js 20, Python 3, yt-dlp, ffmpeg
|
||||
#
|
||||
# Uses Debian slim (not Alpine) because:
|
||||
# - yt-dlp's --impersonate chrome requires curl_cffi (compiled C extension)
|
||||
# - curl_cffi's prebuilt wheels target glibc, not musl
|
||||
# - Debian is more reliable for pip-installed packages with C deps
|
||||
# ─────────────────────────────────────────────────────────
|
||||
|
||||
# ── Stage 1: Install Node.js dependencies ──────────────────
|
||||
FROM node:20-slim AS builder
|
||||
|
||||
WORKDIR /app/server
|
||||
COPY server/package.json server/package-lock.json* ./
|
||||
RUN npm ci --production --ignore-scripts 2>/dev/null || npm install --production --ignore-scripts
|
||||
|
||||
# ── Stage 2: Final runtime image ───────────────────────────
|
||||
FROM node:20-slim AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime dependencies:
|
||||
# - dumb-init: proper PID 1 signal handling in containers
|
||||
# - curl: health checks + yt-dlp binary downloads
|
||||
# - python3 + pip: yt-dlp installation and updates
|
||||
# - ffmpeg: audio extraction, splitting, and duration detection
|
||||
# - ca-certificates: HTTPS for YouTube/Gemini API calls
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
dumb-init \
|
||||
curl \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
ffmpeg \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip3 install --break-system-packages yt-dlp curl_cffi \
|
||||
&& yt-dlp --version
|
||||
|
||||
# Copy Node.js app from builder
|
||||
COPY --from=builder /app/server/node_modules ./server/node_modules/
|
||||
COPY server/package.json ./server/
|
||||
COPY server/index.js ./server/
|
||||
COPY public/ ./public/
|
||||
COPY assets/ ./assets/
|
||||
|
||||
# Copy entrypoint scripts
|
||||
COPY docker_entrypoint.sh /usr/local/bin/docker_entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/docker_entrypoint.sh
|
||||
|
||||
# Create persistent data mount point
|
||||
RUN mkdir -p /data
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
PORT=3001 \
|
||||
DATA_DIR=/data
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
ENTRYPOINT ["dumb-init", "--", "/usr/local/bin/docker_entrypoint.sh"]
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
# YouTube Transcript Summarizer — Mac Setup Guide
|
||||
|
||||
This is a step-by-step guide to get the app running on your Mac. No prior experience with servers or Terminal needed.
|
||||
|
||||
---
|
||||
|
||||
## What you're setting up
|
||||
|
||||
This app has two parts:
|
||||
|
||||
1. **A small server** that runs locally on your Mac (not on the internet — only you can access it). It downloads YouTube audio and talks to Google's Gemini AI.
|
||||
2. **A webpage** you open in your browser that connects to that local server.
|
||||
|
||||
Nothing is uploaded anywhere. Everything runs on your machine.
|
||||
|
||||
---
|
||||
|
||||
## Where to save the project
|
||||
|
||||
The `youtube-summarizer` folder you downloaded from Cowork can live anywhere, but the conventional place for projects like this on a Mac is:
|
||||
|
||||
```
|
||||
~/Projects/youtube-summarizer
|
||||
```
|
||||
|
||||
`~` means your home folder (e.g., `/Users/grant`). If you don't have a `Projects` folder yet, you'll create one below.
|
||||
|
||||
**To move the files there:**
|
||||
|
||||
1. Open **Finder**
|
||||
2. Go to your home folder (press `Cmd + Shift + H`)
|
||||
3. Create a new folder called `Projects` if you don't have one (right-click → New Folder)
|
||||
4. Drag the `youtube-summarizer` folder from your Cowork downloads into `Projects`
|
||||
|
||||
You should end up with this structure:
|
||||
|
||||
```
|
||||
~/Projects/youtube-summarizer/
|
||||
├── public/
|
||||
│ └── index.html ← the app you open in your browser
|
||||
├── server/
|
||||
│ ├── index.js ← the backend server code
|
||||
│ └── package.json ← lists the server's dependencies
|
||||
├── setup.sh ← automatic setup script
|
||||
└── GET-STARTED.md ← this file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Install Node.js (if you don't have it)
|
||||
|
||||
Node.js is what runs the server. Check if you already have it:
|
||||
|
||||
1. Open **Terminal** (press `Cmd + Space`, type "Terminal", hit Enter)
|
||||
2. Type this and press Enter:
|
||||
|
||||
```bash
|
||||
node --version
|
||||
```
|
||||
|
||||
- If you see a version number like `v20.11.0` → you're good, skip to Step 2
|
||||
- If you see "command not found" → install it:
|
||||
1. Go to **https://nodejs.org**
|
||||
2. Download the **LTS** version (the green button)
|
||||
3. Open the downloaded `.pkg` file and follow the installer
|
||||
4. Close and reopen Terminal, then try `node --version` again
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Run the setup script
|
||||
|
||||
This installs yt-dlp (the YouTube audio downloader) and the server's dependencies. In Terminal:
|
||||
|
||||
```bash
|
||||
cd ~/Projects/youtube-summarizer
|
||||
bash setup.sh
|
||||
```
|
||||
|
||||
You should see checkmarks for Node.js, yt-dlp, and the server dependencies. If yt-dlp isn't found and can't auto-install, run:
|
||||
|
||||
```bash
|
||||
brew install yt-dlp
|
||||
```
|
||||
|
||||
(If you don't have Homebrew either, install it first from **https://brew.sh** — it's a one-line Terminal command shown on their homepage.)
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Start the server
|
||||
|
||||
```bash
|
||||
cd ~/Projects/youtube-summarizer/server
|
||||
npm start
|
||||
```
|
||||
|
||||
You should see:
|
||||
|
||||
```
|
||||
YouTube Summarizer API running on http://localhost:3001
|
||||
✓ yt-dlp 2025.x.x (up to date)
|
||||
```
|
||||
|
||||
**Leave this Terminal window open.** The server runs as long as this window is open. To stop it later, press `Ctrl + C`.
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Open the app
|
||||
|
||||
Open the webpage in your browser. The easiest way — open a **new** Terminal tab (`Cmd + T`) and run:
|
||||
|
||||
```bash
|
||||
open ~/Projects/youtube-summarizer/public/index.html
|
||||
```
|
||||
|
||||
Or just double-click `index.html` in Finder. It opens like any webpage.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Add your Gemini API key
|
||||
|
||||
1. In the app, click **"Gemini API Settings"** to expand it
|
||||
2. Paste your Gemini API key into the API Key field
|
||||
3. Pick a model (the default `gemini-2.0-flash` is fast and cheap)
|
||||
|
||||
**Don't have a key yet?** Get one free:
|
||||
1. Go to **https://aistudio.google.com/apikey**
|
||||
2. Sign in with your Google account
|
||||
3. Click "Create API Key"
|
||||
4. Copy the key and paste it in the app
|
||||
|
||||
Your key is saved in your browser's localStorage so you don't have to re-enter it each time.
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Summarize a video
|
||||
|
||||
1. Paste a YouTube URL
|
||||
2. Click **Summarize**
|
||||
3. Watch the 3-step pipeline: Download audio → Transcribe → Analyze topics
|
||||
4. Click any topic section to expand the full transcript with clickable timestamps
|
||||
|
||||
---
|
||||
|
||||
## Day-to-day usage
|
||||
|
||||
Each time you want to use the app:
|
||||
|
||||
1. Open Terminal
|
||||
2. Run:
|
||||
```bash
|
||||
cd ~/Projects/youtube-summarizer/server && npm start
|
||||
```
|
||||
3. Open `index.html` in your browser (bookmark it for easy access)
|
||||
4. When done, press `Ctrl + C` in Terminal to stop the server
|
||||
|
||||
That's it. Two commands.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Cannot connect to backend at localhost:3001"**
|
||||
→ The server isn't running. Go back to Step 3.
|
||||
|
||||
**"yt-dlp not installed"**
|
||||
→ Run `brew install yt-dlp` in Terminal, then restart the server.
|
||||
|
||||
**Download fails or hangs**
|
||||
→ yt-dlp might be outdated. The app will try to auto-update it, but you can also manually run:
|
||||
```bash
|
||||
yt-dlp -U
|
||||
```
|
||||
|
||||
**"Gemini API error: 403" or "401"**
|
||||
→ Your API key is invalid or expired. Get a new one from https://aistudio.google.com/apikey
|
||||
|
||||
**Long videos take a while**
|
||||
→ Normal. A 1-hour video takes ~30 seconds to download audio, then 30-60 seconds for Gemini to transcribe, then another 10-20 seconds for topic analysis. The app shows live progress.
|
||||
|
||||
---
|
||||
|
||||
## Optional: Make it even easier to start
|
||||
|
||||
You can create a shortcut so you just double-click to launch everything. In Terminal:
|
||||
|
||||
```bash
|
||||
cat > ~/Projects/youtube-summarizer/start.command << 'EOF'
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")/server"
|
||||
echo "Starting YouTube Summarizer..."
|
||||
echo "Press Ctrl+C to stop."
|
||||
echo ""
|
||||
npm start
|
||||
EOF
|
||||
chmod +x ~/Projects/youtube-summarizer/start.command
|
||||
```
|
||||
|
||||
Now you have a `start.command` file in the project folder. Double-click it to launch the server — it opens Terminal automatically. Then just open `index.html` in your browser.
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
%PDF-1.4
|
||||
%“Œ‹ž ReportLab Generated PDF document (opensource)
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R /F3 4 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/Contents 15 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Contents 16 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Contents 17 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Contents 18 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
9 0 obj
|
||||
<<
|
||||
/Contents 19 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
10 0 obj
|
||||
<<
|
||||
/Contents 20 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
<<
|
||||
/Contents 21 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
12 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 14 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
13 0 obj
|
||||
<<
|
||||
/Author (\(anonymous\)) /CreationDate (D:20260213152439+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260213152439+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
14 0 obj
|
||||
<<
|
||||
/Count 7 /Kids [ 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1395
|
||||
>>
|
||||
stream
|
||||
Gau0CgN)%,&:N/3lq>Ak@m^Ain`%%-9jDnjeu>&$FN,sF$&Q#\Jd"H@mUYnU?1=RjU1?<)CQBbP"Cf]KF*8@o@,WbU?DALuLCe(d-r:-,$E-<3#iEPSE:VV6Furuj0Q7,KgF"'Il`N5P=,Ag/IHCO7!fI78&F)<JjapZ30Eg3$FWns`+p6trLc.'ZCl\^jMk>_Y9`L?"=>'i2MAK9gdSduWc?$/:ItW+Oi@T`?_qF'?&FP;UctpILAd=:?4Wr&*#qQ9km`_fK+$c=)d#\[J+i?7cW:,q\:HNC-n-Bdrf-O\QBe6]+G'4mWK;UVH-uADAk6^[,Q[*Wp!J7S<\\OmQ;u6H5;D\pHi-6:t3G,KTFQ@fjHn5#Yaj<TJ*i=E4>Q_9\U4c*5Vo9Q<Q@3Y+Z^KRL$]TP>N`Wjg3>N?TV%'V7'/`J3$@#]?_CNtP#piXks"e%@;VcniCS;E8cC[RXTj&e'@NlQ22GqdO@TgqJdFF^=YXuS5EY(9*.=jESjZL_Z''d4&g_]n;(8Imf$8NLX^'B`'4NL]Wn]/n]OP6cYGXr2o<$=)gS`(4L`,-(U!dGE9We+4-]HVcUQ9dOEdLaSrO\$Tqckcefj&?(5@aI6L6^f9*9"E6c8HkG):Q#qD>`fVqgu&`BNBGPJL)Fke@Ti903)#6%\toiK=eVL&8'OrR%=S;eVgHk[T1lUEcY'S=9_6WAD-:u\psJ0d_$9!\:1mO)>`NH3_t).cK\=lKNk1MC](K.('2o_2ft'#gL`"ZefUtG4J[_$76bB%s7;msO8%9s:T\I:ApX%_O7P)Or$[s`I*Nk[?'p0Pom^N@#=C(apY+SS&,/dT1RN?)\VFZ\9:S1Y!?%"O<XCN*AK1lUE'nS3.C<BFJ\_#jUQ??h.N>9?2D!J<=@2d8I?5,FhO]G@Gfoh#rSDG.;:uSc"krCY;9_I5L&pQgi[2/9i=8\I5UFnO.KLhH[%c0[lca-BPC3G9+*mu)Pk-P(R`9HGNNTU@uEbk)2k+\4'Ah(ljS.6$rIDh;PAnrCJHN,O4HuQLYe1=?O%K[m7i/F7j!LDRP6D&/7`R@SdECWW?/[,]g/4CmE,8J;hG46S1M,6Mk]@pJcR5!(urA\75Ae2<(Dp'BZiQ1kt'Lbf'%r;"o/`JqR%)Z$?ddT42/u@ep#CKAu1ZnC^?0!`QL..9.1qruH[)UR^l/A'124/4^(Tg7g'OoMn2WGd(b!+[W*_ZeC7aI'EJ&W<H!UgTp;=Sd=[/G"_mB53\=XfcJP$Q/k`qAHIJ_(\51^V4OCMRXomT;-T1#cIEW^PE@$j&(KGR<9'3b_fAV,\Q#HF2=0p;4h/hflfGF3h;^kn@A*bBfSQdA&Q!G`D$d<rXM'cEj)/m:C$VqkriTgKc[Enh78$HGf~>endstream
|
||||
endobj
|
||||
16 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 294
|
||||
>>
|
||||
stream
|
||||
Gaqcqb>,u0$q9pdMT]HS*bqY..\-_^&;:ROJ`[2(RSGrn(MUHHHos#8#].VgI-ku$'4O`5WjW0#1p.o+PX*in9P2XI.("44oWtN;R;c$9/iGf[lI#>Q"BXuL2aS/=.a&u,`VDEE9N"LS'Rh\PI:A:)VP&;08jW!VfBRJW!T5Gb0H#3oHRB?q3*\]jTJ'GY@<Q(IjP9YPQGN?HEp7r2gNVhW*P!1?L>B(=NQZ,#,29O!LbPPZb@$gG?c6^S=Ql^5[kG>&QW$oE:TTB!Znq!UF/L8^ag6Nm";G`N`W~>endstream
|
||||
endobj
|
||||
17 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1376
|
||||
>>
|
||||
stream
|
||||
Gau0C;/bG`&:Vs/(njtRD6U]3(nA&lGF(sLD,Z!8<Q`Ko0<g;Hle>^#qB#Lf41iKX#@&7*>`_:(mFcElq.AcA5_(NII]!@b0/N)^&0N.?(-mW2&8%QmrTrV:$/+)OO1c+E6&`;5Vd;'G9Yqrt5n]8)#*6\iHVl@j0GN20O'u'sj:K2D7LioI[m)aO"EFN%65uBVn;#5TGHZRT$u.T>o(!3$pFuKd6MLpq4##YRgqX33$V/)[_"YqKllcY0"p-,A>]O<Zi?)3R?n;DdQ=*`u/2co$%a-K5M!k,>&fP[rTUC+:lL+!V9"^\9[E'Z=1gn7)2.o1TN6AghY>(]T_hT,[S7r(@>(_t)8MHKC"^Js6j82>LYdn4YY9WjV]Le]V0sY]-&&o9a72V/#][+C%#%%s]Z[`rSaJ:dQYbI1pHTos'>]a?rRfY]6#h@j.C>qGiI]u;g-Q`1g1'-g9-Zo;);[!sohgF9Mkp+fV@Tr4`E)gH<1JCH1ZJB0=_:0c`?5p4p%P)GT]eHmV0;gd%a=B.!-GHC_d">Q&%C>nG`8+t^cL5.cKS@A)J%Sct+]Ugf@G*54oT`E(0ao!p&WiZ"C59p'F5bHE?GRb<h@Fi/Zr/mm(4,f`<lUC#_Y4dNHV7=K26TjKWC485Gc<7l<[.N4_#DCKQg`XX4MA<fl[>&LDGnBoZ(+9)I#rV+f<-Jo-&^4(2T;s;fNV<>!:j]tXl+Dl6:nRk99jXc4*$O%s)X@97CV4a&DOAF+*S`7(ae;3+pQZd/Ll=M%Sbhd/<eIIU5&2RCE%Yr[!smN(U^A\IB(r+C"u!L'HTgUR2fbX&Mb3]d+;N[m5X!^rk/[EaU6$XP%+0M?HF\CDuh]GS-bo>k4kk'\m6L$i&oW^g^;r%V\mZnGLa-Y@/h.\5u`$/Q=puGfm41$f)*s6:3afuhIfNX\-Y69K^k23c0WBV6PlP+"2bMtjH#\$h$3%m]=gR:@1mr0EMXQNkMIb7cVgNdXI;HD0[Nfs:rU1'jYq?mX#a)nD+D5a\FA#^p7'@K;>4U:XF>VpO*$g??5go\>TlH-g_2[mV*4-p:9iSTV]$?T?rCQi_Fp0$?Dkf7JMdqSD,N@#(L1pm@a-SpTs(l1,nsjl2rf<:C@j!W6bt#c^6sSJ$b4D9S!AS@L6CM7H$]Y.Z+:$)Hu.89a%4CZi>&o5Q?&D"k9(h5o8uL>Jb3tu4-;abWij+pPi*FC\r3T9iB^55a]iSoCM".R6D55-Ce's,'"rjg]U"kI*Im:8i@%5DGVA>*)M+6.A/$EZRF^k(Y)RSkhU3#'X:?iX6W^+Jf7"0SaWaLUdTV:c4+QoSRrZt7Q'F$V6Ppp4;UJ?IjZIsAhA'o;FK6@CpN@%$PQ(ZcR@.7~>endstream
|
||||
endobj
|
||||
18 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 197
|
||||
>>
|
||||
stream
|
||||
GapXOaUZ0A$q0R[MRfu_KK>p2\:WYW"j&t?<TsQj6:h^dHdVm8a^a#!-PMXcMS85('4ZM<O91ak/N*<X$]C@E?S]g$6;D6NLM`ET9(anFIY`]_&qTV7.uatmIAmp[q8-BPM=]Y;ptF_ABC'f/LM>;IE9?O>)NUbV=5t8ol0X;X9RTbsIC0)?^t[tWHP"+#1C>h2~>endstream
|
||||
endobj
|
||||
19 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1482
|
||||
>>
|
||||
stream
|
||||
Gatm:?#SIU'Rf_Z\198_/Rhl4Vr`[7m^a/_!]4]B%0cUF89DdN+uP78k<81@muip+/9[b(8K?KA6sZC2Gj`,/J<)?m5Doa(9b-c="@rOg)G&pXOIs?Bq;dSC)-/)`(I775\/_\uI_8bc&U8ceP:Q`q,a#X:XsP!Cm%Yqi2]+Q*^c.C.`5J3QB\#MWKJV>?U&nUT=LINHaM1%?g2-X:^@#g.UtMtp!+$4,R?-7!rOHiJb_Ohu;S-^NnIG'?Cq&g9ZrC`M^;q?FHHe]n,])Z[mn9T2YiQ.b,W1AfY6X<BP`QSn1$&,o!m(d9&uLG'iuL]:[NtYam`/@L.:BQ:\$EcMfrV,tnK#>='e<hD0N#.Hl`1VR8<S[I8<5"WL8:TO_Xnib-.krSn%rK^Sf^i8(Oab/`W'Di1OuDPLNU4j;r@_cZ<,C&q2H+-f!6or!aH)omA.8c*_lih\O6^Jfcgb0ZC(kA:,9_aJ-]`pLm#tT+<dEIJ7%%R\+3"*LR)YlnrUBsV&-$VEKe,//PslU"d=@PUr$-061]i%5XUHj(\kOp%c:;X]Oju:nP[7N"5,HG9)P`_IE+%DQQ</mCbTA_"YZ:jI*HY"af\d+X-EpflWrdSD%p1$(8GtE;#I?A"$sQ$:8"P]`6\V:_2nc!Ko$cFh6dpfQiIr]0b9ZC1-:bkf(-u6L(s:r"@LC8(Sq7eE=Z0/JrQ=kT0Bi(KCER5XrqAWiI]Xb5rm'sIathPgSP5s;qEEJHaPZ`4L#O*d^rJ!e*V&$?H\(<?I0Us1'('L(h0*LP4(\C;0-b_s6suF;+?R,5STDpFFZ<nIJtI1K&hb(H+Go0@C`[$;J)jJ.N<+TfSCW(RHZ#]+4'IkWK:`:b&aTH,?Z,qOG-%:%Y>t7%8D`nrgo`D$gHdZ;"p;mf'Vj;m`p<3L8&OT%/ttT0%qS"U,D)1\?(F&C<N_,O`QZsHR*p_NDm[#d^i`0kI!\a<jL2td.bX&hn3U:]pfLp*\"bK=m!Qn+H)koLW@T-/cZT76\gj9UC*1'!UY^%^[P"F1S%<MZ(;rfRqk/?hD;5M%]f2"\6rK]ERh`^kYF\$/aYB9`1"[&fleWnkcolNbNkhF!Y<TDY1-QiNbX<pT?cqRSJbjg_5$.emI^aL?,?Pj1.)S$5"ac4>Xoq3nPe+s4SYK4@1E]YSInoG>@oGlLS'R),q[NV9.jZH'BG%.Y#$*@_uEbNMd'/QQ7Xc$LVXT[T-o5MGC38mFaITl.BH>*iNYUO,:PQ[@_^:me5g)Zd?W01`OX%7'Bi:f3sI]>N`IlkT/mI3\YXO,(3__@QZkRs3b^ZB.F!P+k%'>?eI3fC]ZW/dC/,8F)6kD!-+aJ$KC9<aDm@)Lfsi8QV/PM,aRff6oH*0Uo3_YtRc6Tq6OajP6>"&T(ti-)SS:+%0DO>MWtE#mO-TTj['/&,BWY1:R3<%DV#(qkV7ahDY%!:Im"#7r-2uKV[:f>R+,7m%V8%>t~>endstream
|
||||
endobj
|
||||
20 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 410
|
||||
>>
|
||||
stream
|
||||
GatUn;,>(P'SYH=/'aWTEEHCF[TB4fR2@^mA$Qp%ieD5W!d2mt0C?1bkE8!L9n6Ko]mM1mOiF'm>W0BW_"Bhobog=Y).='e\.aMh!So76:,6cLNq/QsqSPV=:d?k1]W:;/d&p$+PAJI?BjC7Y^b([FJm6t^C,IJV?*5o8G`,St^+,NSklPI6dn$COPU!#a>>t2UES3W@`AdoLVJHK\o%$aL5G1+-,U7Q=Xi&$/X]H!UUPstEK5G/GV6&uYN(2Gj*u&7`(%">]en0o_LS[.daRfEUjoj!\APcO)Y#*^#.tj1>:p/28f%=_9fknsTd.=:Fo-CEELC\RgHZA]OU"k$?L:6;QqJVs"p+@cT"lg`48GRp-90(8mZ'Ft>,l?ss7)B<B*=*^GMM?S/"??P$i#BfnWc\~>endstream
|
||||
endobj
|
||||
21 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1025
|
||||
>>
|
||||
stream
|
||||
Gatm:bAu>q']&X:mV#P,A'k:mLZD_^D5K+W]Z`">KLhIu$j%s[>#?(6p0L"KSMZ5WNZuc))N_Jli1,]-;':,2pg*UocRZO%N<2hJ\cnNK)-!fufBVA!$Tbt(PXu3..I_I"9h<!)V\paj6g1CtKGI^8B\NnG73ANG;"[pNKp785BbBV_.r3/,'!=%19ATRUeOQQe$$bq/qA3a@DC/%L910(gUg,-fas\dnpG"+VX!o9*cg/&!YVZ,'%qZ@kDEPBLDT9ER<dkfBW=AjVbmYOl*nYi@M)qF`J0(AXO:`Dg:XVA[&A5@E6*d`m+PY2FC*i1-n=>)6WPg+4W.krsi?-`+h]gZdlr\FV)5_+-<;8*[5jF0d6p4`<pWuI69Ue;t8I%_c4`l(eM=.nMjaieA*k^i.18@G[<V^g.OrrZ=iW[rfGc6VQU..TV[_0<f\cM4bR@:2%3.K0YTo5h:k3Mr0J&VGlYDP[#HXT4Ocq\c6)V[6&Qa*Yo?hqR!*^&+o?[B[q0(k1]H't9=4O;VD7.@ls2/7Xa]%##HV*m,;/BW%2Z6)R7NGMfLG"3$]TQR9H.q*e(\XKs]'oJ'`mUFdXB@"\fZI<hXjP<sZ^,.pR$ub'i9838fibm5IH^[l6A7m:7A7H\_#IX]XkSrqYPJE*3oND)HKJE+F[t*l0^!Xm15iF<t>PgQj`hBfQ&J(Qin'?q)=e;0@,!3g4R=5$++:AM%hYdr$>%=`Z,A[tC\B&9g,K&R3bRX[%N&IEfM*7^@.W`q$C]XY-Bok5To1F8cTM]$j0nZUm&)nrnbK4@Up$h0V3@()Yk/A[umCXOrp!jeDcB!rA8S_##7*(`G5"J)2=W0k-lHYE0H(OH-NGd]]2SqHCr!kdrFrd0#:Qo8@PUIou4Lm*d%@E77(u&QP_)%ab/r1TP6kU"/AgA@Q7Q2ri.F#4o07f6cnbD;`h3f2%S&YWZEp[Tl[pmK"8lk3.PIqcD%34,On"^>hD;8'?IscDLPe7ed=OUI4gs!K?C^MT#p]i[?EFJ~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 22
|
||||
0000000000 65535 f
|
||||
0000000061 00000 n
|
||||
0000000112 00000 n
|
||||
0000000219 00000 n
|
||||
0000000331 00000 n
|
||||
0000000436 00000 n
|
||||
0000000631 00000 n
|
||||
0000000826 00000 n
|
||||
0000001021 00000 n
|
||||
0000001216 00000 n
|
||||
0000001411 00000 n
|
||||
0000001607 00000 n
|
||||
0000001803 00000 n
|
||||
0000001873 00000 n
|
||||
0000002154 00000 n
|
||||
0000002252 00000 n
|
||||
0000003739 00000 n
|
||||
0000004124 00000 n
|
||||
0000005592 00000 n
|
||||
0000005880 00000 n
|
||||
0000007454 00000 n
|
||||
0000007955 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<f489779f8c1c153720fb5c785d0c5179><f489779f8c1c153720fb5c785d0c5179>]
|
||||
% ReportLab generated PDF document -- digest (opensource)
|
||||
|
||||
/Info 13 0 R
|
||||
/Root 12 0 R
|
||||
/Size 22
|
||||
>>
|
||||
startxref
|
||||
9072
|
||||
%%EOF
|
||||
@@ -0,0 +1,10 @@
|
||||
Proprietary License
|
||||
|
||||
Copyright (c) 2026. All rights reserved.
|
||||
|
||||
This software and associated documentation files (the "Software") are
|
||||
proprietary. Unauthorized copying, modification, distribution, or use
|
||||
of this Software, via any medium, is strictly prohibited without prior
|
||||
written permission from the copyright holder.
|
||||
|
||||
The Software is provided "as is", without warranty of any kind.
|
||||
@@ -0,0 +1,2 @@
|
||||
# overrides to s9pk.mk must precede the include statement
|
||||
include s9pk.mk
|
||||
@@ -0,0 +1,842 @@
|
||||
# YouTube Summarizer: StartOS 0.4.0 Packaging Game Plan
|
||||
|
||||
**Date:** April 9, 2026
|
||||
**Status:** Feasibility Assessment & Implementation Roadmap
|
||||
**Target:** StartOS 0.4.0 Beta (s9pk package format)
|
||||
**Reference:** Workout Log packaging for StartOS 0.3.5
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Packaging the YouTube Summarizer for StartOS 0.4.0 is **feasible** but presents unique challenges that a typical web app does not. The app is more than a simple CRUD service -- it downloads audio from YouTube (requiring yt-dlp to always be current), authenticates against YouTube to bypass bot detection, transcribes audio via the Gemini API, and manages podcast RSS feeds. Running this on a headless remote server introduces three core challenges that require thoughtful solutions:
|
||||
|
||||
1. **yt-dlp must stay current** -- YouTube changes its anti-bot signatures regularly, so a stale yt-dlp binary means broken downloads within days or weeks.
|
||||
2. **YouTube authentication without a local browser** -- The current app relies on cookies from your local browser or a cookies.txt file. A remote server has no browser session.
|
||||
3. **Server/datacenter IP reputation** -- YouTube is more aggressive about blocking downloads from non-residential IPs.
|
||||
|
||||
All three are solvable. This document lays out the approach for each, plus the full packaging plan.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Current App Architecture](#1-current-app-architecture)
|
||||
2. [What Changes for StartOS](#2-what-changes-for-startos)
|
||||
3. [Challenge 1: Keeping yt-dlp Updated](#3-challenge-1-keeping-yt-dlp-updated)
|
||||
4. [Challenge 2: YouTube Authentication on a Headless Server](#4-challenge-2-youtube-authentication-on-a-headless-server)
|
||||
5. [Challenge 3: Server IP Bot Detection](#5-challenge-3-server-ip-bot-detection)
|
||||
6. [StartOS 0.4.0 Packaging Structure](#6-startos-040-packaging-structure)
|
||||
7. [Differences from v0.3.5 Packaging (Workout Log)](#7-differences-from-v035-packaging-workout-log)
|
||||
8. [Implementation Phases](#8-implementation-phases)
|
||||
9. [Persistent Data Contract](#9-persistent-data-contract)
|
||||
10. [Ongoing Maintenance Plan](#10-ongoing-maintenance-plan)
|
||||
11. [Risk Assessment](#11-risk-assessment)
|
||||
12. [Multi-User Distribution: API Keys and Clean Installs](#12-multi-user-distribution-api-keys-and-clean-installs)
|
||||
13. [Appendix A: File-by-File Packaging Checklist](#appendix-a-file-by-file-packaging-checklist)
|
||||
14. [Appendix B: Reusable Packaging Roadmap for Future Apps](#appendix-b-reusable-packaging-roadmap-for-future-apps)
|
||||
|
||||
---
|
||||
|
||||
## 1. Current App Architecture
|
||||
|
||||
The YouTube Summarizer is a Node.js application with these components:
|
||||
|
||||
**Backend (server/index.js -- ~1800 lines):**
|
||||
- Express.js server on port 3001
|
||||
- Calls yt-dlp as a child process to download audio from YouTube
|
||||
- Downloads podcast episodes directly via HTTP
|
||||
- Uploads audio to Google Gemini File API for transcription
|
||||
- Runs topic analysis via Gemini (multiple model fallback chain)
|
||||
- Manages subscriptions (YouTube channels + podcast RSS feeds)
|
||||
- Auto-queue system: checks subscriptions for new content, queues for approval
|
||||
- Cookie management: supports cookies.txt file and --cookies-from-browser flag
|
||||
- yt-dlp auto-update: checks GitHub releases every 24h, updates via self-update / brew / pip
|
||||
- History storage: JSON files on disk (not a database)
|
||||
- Health check endpoint at /api/health
|
||||
- Heartbeat/auto-sleep system (shuts down when no browser connected for 30s)
|
||||
|
||||
**Frontend (public/index.html):**
|
||||
- Single-page app, served as static files by Express
|
||||
- Split-screen layout: video embed + topic summaries
|
||||
- Subscription management UI
|
||||
- Cookie upload/test UI
|
||||
- Settings panel for API key and model selection
|
||||
|
||||
**External Dependencies:**
|
||||
- yt-dlp (system binary, called via child_process)
|
||||
- ffmpeg (required by yt-dlp for audio extraction)
|
||||
- Node.js 20+
|
||||
- Google Gemini API (requires API key)
|
||||
|
||||
**Data Storage (all in /history/ directory):**
|
||||
- Individual summary JSON files (one per processed video/podcast)
|
||||
- subscriptions.json (channel/feed list)
|
||||
- _meta.json (folder structure for organizing summaries)
|
||||
- seen-list.json, skip-list.json (dedup tracking)
|
||||
- auto-queue.json (pending items from subscription checks)
|
||||
- cookies.txt (YouTube authentication)
|
||||
- .env (Gemini API key, cookie browser preference)
|
||||
|
||||
---
|
||||
|
||||
## 2. What Changes for StartOS
|
||||
|
||||
### Things That Work As-Is
|
||||
- The Express server, Gemini API integration, and frontend are platform-agnostic
|
||||
- Podcast RSS feed parsing (direct HTTP, no auth needed)
|
||||
- History/subscription JSON storage
|
||||
- Health check endpoint
|
||||
|
||||
### Things That Need Adaptation
|
||||
|
||||
| Current Behavior | StartOS Adaptation |
|
||||
|---|---|
|
||||
| Runs on macOS with Homebrew | Docker container on Alpine Linux (ARM64) |
|
||||
| yt-dlp installed via brew | yt-dlp installed via pip in container, self-updates at runtime |
|
||||
| Cookies from local Firefox/Chrome | cookies.txt uploaded via web UI (already supported) + OAuth2 |
|
||||
| Auto-sleep when no browser connected | Remove sleep logic; service runs continuously |
|
||||
| Hardcoded port 3001 | Configurable, default 3001, mapped via StartOS interfaces |
|
||||
| .env file for config | StartOS config UI (manifest config spec) |
|
||||
| macOS .app bundle / launcher | Not needed; StartOS manages service lifecycle |
|
||||
| LAN mode dialog | Not needed; StartOS handles network exposure (Tor + LAN) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Challenge 1: Keeping yt-dlp Updated
|
||||
|
||||
### The Problem
|
||||
YouTube frequently changes its download mechanisms and anti-bot measures. A yt-dlp version that works today may stop working within 1-2 weeks. The app already handles this with a multi-strategy auto-update (self-update, brew, pip), but inside a Docker container on StartOS, brew is not available and we need a reliable update path.
|
||||
|
||||
### The Solution: Runtime Self-Update with Persistent Storage
|
||||
|
||||
**Strategy:**
|
||||
1. Install yt-dlp via pip at Docker **build time** (gives a known-good starting point)
|
||||
2. Store the yt-dlp binary on the **persistent volume** (`/data/bin/yt-dlp`) so updates survive container restarts
|
||||
3. On each container start, check if the persistent binary exists and is newer than the built-in one; use whichever is newer
|
||||
4. The existing auto-update logic runs `yt-dlp -U` (self-update) which writes to the pip site-packages, but we can also add a dedicated update mechanism that downloads the latest binary directly from GitHub releases to `/data/bin/yt-dlp`
|
||||
|
||||
**Implementation in docker_entrypoint.sh:**
|
||||
```bash
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
DATA_DIR="/data"
|
||||
BIN_DIR="$DATA_DIR/bin"
|
||||
YTDLP_LOCAL="$BIN_DIR/yt-dlp"
|
||||
|
||||
mkdir -p "$BIN_DIR" "$DATA_DIR/history" "$DATA_DIR/config"
|
||||
|
||||
# Use persistent yt-dlp if available, otherwise fall back to system
|
||||
if [ -x "$YTDLP_LOCAL" ]; then
|
||||
export PATH="$BIN_DIR:$PATH"
|
||||
echo "Using persistent yt-dlp: $($YTDLP_LOCAL --version)"
|
||||
else
|
||||
echo "Using system yt-dlp: $(yt-dlp --version)"
|
||||
fi
|
||||
|
||||
# Start the Node.js server
|
||||
exec node /app/server/index.js
|
||||
```
|
||||
|
||||
**Auto-update enhancement in server code:**
|
||||
- Modify `autoUpdateYtdlp()` to: (1) try `yt-dlp -U`, (2) try `pip install -U yt-dlp`, (3) as a last resort, download the latest binary directly from `https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp` and save to `/data/bin/yt-dlp`
|
||||
- Add a scheduled check: on server startup and every 12 hours, check for updates
|
||||
- Expose update status in the health check endpoint so StartOS can surface it
|
||||
|
||||
**Why this works on StartOS:**
|
||||
- `/data` is the persistent StartOS volume; it survives container restarts and package upgrades
|
||||
- The container image provides a baseline yt-dlp that works at build time
|
||||
- Runtime updates keep it fresh without rebuilding the entire package
|
||||
- If a runtime update breaks something, removing `/data/bin/yt-dlp` reverts to the built-in version
|
||||
|
||||
### Also: ffmpeg
|
||||
ffmpeg is a build-time dependency (Alpine package `ffmpeg`). It rarely needs updates for this use case, so installing it in the Dockerfile is sufficient. It is updated whenever you rebuild and push a new package version.
|
||||
|
||||
---
|
||||
|
||||
## 4. Challenge 2: YouTube Authentication on a Headless Server
|
||||
|
||||
### The Problem
|
||||
YouTube increasingly requires authentication to download content. The current app supports two methods:
|
||||
1. **cookies.txt file** -- a Netscape-format cookie export from a browser
|
||||
2. **--cookies-from-browser** -- reads cookies directly from a local browser's cookie store
|
||||
|
||||
On a remote StartOS server, there is no local browser, so method 2 is unavailable.
|
||||
|
||||
### The Solution: Three-Tier Authentication
|
||||
|
||||
**Tier 1: OAuth2 Device Flow (Primary -- Best Option)**
|
||||
|
||||
yt-dlp now supports OAuth2 authentication with a device code flow, which is perfect for headless servers:
|
||||
|
||||
```bash
|
||||
yt-dlp --username oauth --password '' <URL>
|
||||
```
|
||||
|
||||
How it works:
|
||||
- On first use, yt-dlp prints a code and a URL (https://www.google.com/device)
|
||||
- The user opens that URL on any device (phone, laptop) and enters the code
|
||||
- A refresh token is cached in yt-dlp's cache directory
|
||||
- All subsequent downloads use the cached token -- no further interaction needed
|
||||
|
||||
For StartOS integration:
|
||||
- Mount yt-dlp's cache directory on the persistent volume (`/data/ytdlp-cache/`)
|
||||
- Add a "Setup YouTube Auth" action in the StartOS manifest that triggers the OAuth flow and displays the device code in the service logs or a dedicated endpoint
|
||||
- Build a simple UI page in the web frontend that shows the device code and instructions
|
||||
- The token persists across restarts because it lives on `/data`
|
||||
|
||||
**Tier 2: cookies.txt Upload (Fallback)**
|
||||
|
||||
The app already has a full cookies.txt management system via the web UI:
|
||||
- Upload endpoint: POST /api/cookies/upload
|
||||
- Test endpoint: POST /api/cookies/test
|
||||
- Status endpoint: GET /api/cookies/status
|
||||
- Delete endpoint: POST /api/cookies/delete
|
||||
|
||||
This works on StartOS as-is. The cookies.txt file should be stored on the persistent volume (`/data/cookies.txt`) instead of the project root.
|
||||
|
||||
**Important caveat:** YouTube cookies expire in approximately 3-5 days. This means the user would need to re-export and re-upload cookies regularly. This is why OAuth2 is the recommended primary method.
|
||||
|
||||
**Tier 3: No Authentication (Limited)**
|
||||
|
||||
Some YouTube content can be downloaded without any authentication. The app already handles this gracefully -- it attempts download without cookies if cookie-based download fails. This will work for some videos but not all, especially age-restricted or bot-flagged content.
|
||||
|
||||
### Implementation Priority
|
||||
1. Add OAuth2 support to the server code (new endpoint to initiate flow, display code, check status)
|
||||
2. Move cookies.txt storage to persistent volume
|
||||
3. Remove --cookies-from-browser logic (not applicable on remote server)
|
||||
4. Add a clear "Authentication Setup" section in the web UI that guides through OAuth2 first, cookies.txt as backup
|
||||
|
||||
---
|
||||
|
||||
## 5. Challenge 3: Server IP Bot Detection
|
||||
|
||||
### The Problem
|
||||
YouTube maintains IP reputation databases. Residential ISP IPs (like your home connection) are generally trusted, but datacenter IPs are frequently flagged. A Start9 server running at home on your residential IP should actually be fine -- this is a significant advantage of self-hosted infrastructure.
|
||||
|
||||
### Assessment: Low Risk for Start9 Home Servers
|
||||
|
||||
**Start9 servers typically run at home on a residential IP.** This means:
|
||||
- The server's IP is a normal residential ISP address
|
||||
- YouTube treats these the same as any home computer
|
||||
- Bot detection is primarily triggered by datacenter/cloud IPs (AWS, GCP, Azure, etc.)
|
||||
- Rate limiting may still occur with heavy usage, but this is the same as running the app on your Mac
|
||||
|
||||
**When it could be a problem:**
|
||||
- If you access the Start9 server through a VPN and route yt-dlp traffic through the VPN
|
||||
- If your ISP uses CGNAT (carrier-grade NAT) which shares IPs with many users
|
||||
- If you process a very high volume of downloads in a short period
|
||||
|
||||
### Mitigation Strategies (Built Into the App)
|
||||
|
||||
The app already has several mitigations that carry over directly:
|
||||
|
||||
1. **Retry with exponential backoff** -- the download logic already retries with 30s, 60s, 120s delays when rate-limited
|
||||
2. **Cookie/OAuth authentication** -- authenticated requests are less likely to trigger bot detection
|
||||
3. **yt-dlp auto-update** -- newer yt-dlp versions include workarounds for the latest YouTube anti-bot measures
|
||||
|
||||
**Additional measures to add for StartOS:**
|
||||
1. **Rate limiting between downloads** -- when processing auto-queue items from subscriptions, add configurable delays between downloads (e.g., 30-60 seconds between videos)
|
||||
2. **Download scheduling** -- spread subscription checks and downloads across the day rather than bursting
|
||||
3. **Proxy support (optional)** -- add a config option for users to specify a SOCKS5 or HTTP proxy if they want to route yt-dlp traffic through a specific connection. This is an advanced option, not required for most users.
|
||||
4. **Browser impersonation** -- yt-dlp supports `--impersonate chrome` which mimics Chrome's TLS fingerprint. Add this as a default argument.
|
||||
|
||||
### Summary
|
||||
For a home Start9 server, YouTube bot detection is **not a significant concern**. The residential IP is the same one you'd be using from your Mac. Combined with OAuth2 authentication and yt-dlp staying current, this should work reliably.
|
||||
|
||||
---
|
||||
|
||||
## 6. StartOS 0.4.0 Packaging Structure
|
||||
|
||||
### Key Changes from 0.3.5
|
||||
|
||||
StartOS 0.4.0 is a complete rewrite. The major packaging-relevant changes:
|
||||
|
||||
| Aspect | 0.3.5 | 0.4.0 |
|
||||
|---|---|---|
|
||||
| Container runtime | Podman | LXC (Linux Containers) |
|
||||
| Package format | s9pk (same name, different internals) | s9pk with signatures, partial downloads, multi-arch |
|
||||
| Dev tooling | Shell/make-based | TypeScript SDK available |
|
||||
| Networking | Tor + LAN | Same, with improved LAN port forwarding |
|
||||
| Backups | Not compatible across versions | Fresh backups required after migration |
|
||||
|
||||
### Package Files Needed
|
||||
|
||||
Based on the workout-log template and v0.4.0 documentation:
|
||||
|
||||
```
|
||||
start9/
|
||||
0.4/
|
||||
manifest.yaml # Service metadata, config spec, interfaces
|
||||
Dockerfile # Multi-stage build for ARM64
|
||||
docker_entrypoint.sh # Service startup script
|
||||
healthcheck.sh # Health check script
|
||||
Makefile # Build automation
|
||||
instructions.md # User-facing documentation
|
||||
LICENSE # License file
|
||||
icon.png # Service icon
|
||||
DEPLOY.md # Deploy/sideload instructions
|
||||
```
|
||||
|
||||
### Draft manifest.yaml
|
||||
|
||||
```yaml
|
||||
id: youtube-summarizer
|
||||
title: YouTube Summarizer
|
||||
version: 0.1.0.1
|
||||
release-notes: >-
|
||||
Initial StartOS package. YouTube/podcast audio download,
|
||||
transcription via Gemini, and topic analysis.
|
||||
license: Proprietary
|
||||
wrapper-repo: https://github.com/user/youtube-summarizer-startos
|
||||
upstream-repo: https://github.com/user/youtube-summarizer
|
||||
support-site: https://github.com/user/youtube-summarizer/issues
|
||||
marketing-site: https://github.com/user/youtube-summarizer
|
||||
build: ["make image-arm"]
|
||||
|
||||
description:
|
||||
short: Download, transcribe, and summarize YouTube videos and podcasts.
|
||||
long: >-
|
||||
YouTube Summarizer downloads audio from YouTube videos and podcast feeds,
|
||||
transcribes them using Google Gemini, and produces structured topic
|
||||
summaries. Supports subscriptions with automatic new episode detection,
|
||||
organized history with folders, and a responsive web interface.
|
||||
|
||||
assets:
|
||||
license: LICENSE
|
||||
icon: icon.png
|
||||
instructions: instructions.md
|
||||
docker-images: image.tar
|
||||
|
||||
main:
|
||||
type: docker
|
||||
image: main
|
||||
entrypoint: docker_entrypoint.sh
|
||||
args: []
|
||||
mounts:
|
||||
main: /data
|
||||
|
||||
health-checks:
|
||||
main:
|
||||
name: API health
|
||||
success-message: YouTube Summarizer is responding.
|
||||
type: docker
|
||||
image: main
|
||||
entrypoint: healthcheck.sh
|
||||
args: []
|
||||
inject: true
|
||||
|
||||
config:
|
||||
get:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- cat /data/config/startos-config.json 2>/dev/null || echo '{}'
|
||||
set:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- cat > /data/config/startos-config.json
|
||||
|
||||
dependencies: {}
|
||||
|
||||
volumes:
|
||||
main:
|
||||
type: data
|
||||
|
||||
interfaces:
|
||||
main:
|
||||
name: Web Interface
|
||||
description: Browser UI for YouTube Summarizer.
|
||||
tor-config:
|
||||
port-mapping:
|
||||
80: "3001"
|
||||
lan-config:
|
||||
443:
|
||||
ssl: true
|
||||
internal: 3001
|
||||
ui: true
|
||||
protocols: [tcp, http, https]
|
||||
|
||||
backup:
|
||||
create:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
rm -rf /backup/*
|
||||
cp -a /data/. /backup/
|
||||
mounts:
|
||||
main: /data
|
||||
BACKUP: /backup
|
||||
restore:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
cp -a /backup/. /data/
|
||||
mounts:
|
||||
main: /data
|
||||
BACKUP: /backup
|
||||
|
||||
actions:
|
||||
update-ytdlp:
|
||||
name: Update yt-dlp
|
||||
description: Downloads the latest version of yt-dlp for YouTube compatibility.
|
||||
warning: This may take a minute. Service will continue running.
|
||||
implementation:
|
||||
type: docker
|
||||
image: main
|
||||
system: false
|
||||
entrypoint: sh
|
||||
args:
|
||||
- -c
|
||||
- pip install --upgrade yt-dlp && yt-dlp --version
|
||||
inject: true
|
||||
```
|
||||
|
||||
### Draft Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy server package files and install deps
|
||||
COPY server/package.json server/package-lock.json ./server/
|
||||
RUN cd server && npm ci --production
|
||||
|
||||
# Copy application files
|
||||
COPY server/index.js ./server/
|
||||
COPY public/ ./public/
|
||||
COPY assets/ ./assets/
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk add --no-cache \
|
||||
dumb-init \
|
||||
curl \
|
||||
python3 \
|
||||
py3-pip \
|
||||
ffmpeg \
|
||||
&& pip3 install --break-system-packages yt-dlp \
|
||||
&& addgroup -S appgroup -g 1001 \
|
||||
&& adduser -S appuser -u 1001 -G appgroup
|
||||
|
||||
# Copy app from builder
|
||||
COPY --from=builder --chown=appuser:appgroup /app ./
|
||||
|
||||
# Copy StartOS scripts
|
||||
COPY start9/0.4/docker_entrypoint.sh /usr/local/bin/docker_entrypoint.sh
|
||||
COPY start9/0.4/healthcheck.sh /usr/local/bin/healthcheck.sh
|
||||
RUN chmod +x /usr/local/bin/docker_entrypoint.sh /usr/local/bin/healthcheck.sh
|
||||
|
||||
# Create data directory
|
||||
RUN mkdir -p /data && chown -R appuser:appgroup /data
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
PORT=3001
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
ENTRYPOINT ["dumb-init", "--", "/usr/local/bin/docker_entrypoint.sh"]
|
||||
```
|
||||
|
||||
### Draft docker_entrypoint.sh
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
DATA_DIR="/data"
|
||||
HISTORY_DIR="$DATA_DIR/history"
|
||||
CONFIG_DIR="$DATA_DIR/config"
|
||||
BIN_DIR="$DATA_DIR/bin"
|
||||
CACHE_DIR="$DATA_DIR/ytdlp-cache"
|
||||
COOKIES_PATH="$DATA_DIR/cookies.txt"
|
||||
|
||||
# Create directory structure
|
||||
mkdir -p "$HISTORY_DIR" "$CONFIG_DIR" "$BIN_DIR" "$CACHE_DIR"
|
||||
|
||||
# Use persistent yt-dlp binary if it exists and is executable
|
||||
if [ -x "$BIN_DIR/yt-dlp" ]; then
|
||||
export PATH="$BIN_DIR:$PATH"
|
||||
fi
|
||||
|
||||
# Point yt-dlp cache to persistent storage (for OAuth tokens, etc.)
|
||||
export XDG_CACHE_HOME="$CACHE_DIR"
|
||||
|
||||
# Load config from StartOS config file if it exists
|
||||
if [ -f "$CONFIG_DIR/startos-config.json" ]; then
|
||||
# Extract Gemini API key from config
|
||||
GEMINI_KEY=$(cat "$CONFIG_DIR/startos-config.json" | python3 -c "import sys,json; print(json.load(sys.stdin).get('gemini_api_key',''))" 2>/dev/null || echo "")
|
||||
if [ -n "$GEMINI_KEY" ]; then
|
||||
export GEMINI_API_KEY="$GEMINI_KEY"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Also check for .env in data dir
|
||||
if [ -f "$DATA_DIR/.env" ]; then
|
||||
export $(grep -v '^#' "$DATA_DIR/.env" | xargs)
|
||||
fi
|
||||
|
||||
export PORT="${PORT:-3001}"
|
||||
export HOSTNAME="0.0.0.0"
|
||||
|
||||
echo "Starting YouTube Summarizer..."
|
||||
echo " yt-dlp version: $(yt-dlp --version 2>/dev/null || echo 'not found')"
|
||||
echo " ffmpeg: $(ffmpeg -version 2>/dev/null | head -1 || echo 'not found')"
|
||||
echo " Data dir: $DATA_DIR"
|
||||
|
||||
exec node /app/server/index.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Differences from v0.3.5 Packaging (Workout Log)
|
||||
|
||||
The workout-log package was a relatively straightforward Next.js app with a SQLite database. YouTube Summarizer is significantly more complex:
|
||||
|
||||
| Aspect | Workout Log (0.3.5) | YouTube Summarizer (0.4.0) |
|
||||
|---|---|---|
|
||||
| App framework | Next.js + Prisma + SQLite | Express.js + JSON files |
|
||||
| External binaries | None | yt-dlp, ffmpeg |
|
||||
| External APIs | None | Google Gemini API |
|
||||
| Authentication | App-level (user/pass) | YouTube OAuth + cookies |
|
||||
| Data storage | Single SQLite DB | Multiple JSON files + temp audio |
|
||||
| Network access | Inbound only | Inbound + outbound (YouTube, Gemini, RSS) |
|
||||
| Binary updates | None needed | yt-dlp must stay current |
|
||||
| Temp file management | None | Large audio files downloaded and cleaned up |
|
||||
| Container size | Small (~100MB) | Larger (~300-500MB with ffmpeg + yt-dlp + Python) |
|
||||
|
||||
### Key Differences in Packaging Approach
|
||||
|
||||
1. **Outbound network access:** The workout-log only needed to accept inbound connections. YouTube Summarizer needs outbound access to YouTube, Google Gemini API, and podcast RSS feeds. StartOS containers have outbound network access by default, so this works, but it's worth verifying in the 0.4.0 LXC environment.
|
||||
|
||||
2. **Larger image size:** Adding Python, pip, yt-dlp, and ffmpeg significantly increases the Docker image. Expect 300-500MB vs. ~100MB for workout-log. This is acceptable but worth minimizing where possible.
|
||||
|
||||
3. **Runtime binary management:** The entrypoint must handle a mutable binary (yt-dlp) that updates at runtime. The workout-log had no such requirement.
|
||||
|
||||
4. **Temporary file cleanup:** Audio files are downloaded to /tmp during processing and should be cleaned up. Need to ensure the container's /tmp has sufficient space or use the persistent volume with cleanup logic.
|
||||
|
||||
5. **Config complexity:** Workout-log had no configuration. YouTube Summarizer needs at minimum a Gemini API key, and optionally proxy settings, download rate limits, and authentication preferences. This maps to the StartOS config spec in the manifest.
|
||||
|
||||
---
|
||||
|
||||
## 8. Implementation Phases
|
||||
|
||||
### Phase 1: Prepare the App for Headless Operation (Estimated: 1-2 days)
|
||||
|
||||
Code changes to server/index.js before any packaging work:
|
||||
|
||||
1. **Remove auto-sleep logic** -- the heartbeat/sleep system is designed for a desktop app that shuts down when you close the browser. On StartOS, the service should run continuously.
|
||||
|
||||
2. **Move all data paths to a configurable base directory** -- currently paths are relative to the project root. Change to use an environment variable (e.g., `DATA_DIR=/data`) so the persistent volume can be targeted.
|
||||
|
||||
3. **Add OAuth2 authentication flow** -- new endpoints:
|
||||
- POST /api/auth/oauth/start -- initiates OAuth device flow, returns device code
|
||||
- GET /api/auth/oauth/status -- checks if OAuth token has been cached
|
||||
- The web UI gets a new "Authentication" section in Settings
|
||||
|
||||
4. **Enhance yt-dlp update logic for Linux/container** -- remove Homebrew strategy, add direct binary download from GitHub releases as a fallback.
|
||||
|
||||
5. **Add download rate limiting** -- configurable delay between auto-queue downloads (default 30s).
|
||||
|
||||
6. **Add browser impersonation flag** -- pass `--impersonate chrome` to yt-dlp by default when available.
|
||||
|
||||
7. **Remove macOS-specific code** -- the .app bundle creation, osascript dialogs, LAN mode prompt, etc. are not needed.
|
||||
|
||||
### Phase 2: Create the StartOS Package Scaffold (Estimated: 1 day)
|
||||
|
||||
1. Create `start9/0.4/` directory with all packaging files (see Section 6)
|
||||
2. Write Dockerfile with multi-stage build
|
||||
3. Write docker_entrypoint.sh
|
||||
4. Write healthcheck.sh
|
||||
5. Write manifest.yaml with full config spec
|
||||
6. Write instructions.md
|
||||
7. Copy icon.png
|
||||
8. Create Makefile
|
||||
|
||||
### Phase 3: Build, Test, and Iterate (Estimated: 2-3 days)
|
||||
|
||||
1. Build ARM64 Docker image: `make -C start9/0.4 image-arm`
|
||||
2. Smoke test locally:
|
||||
- `docker load -i start9/0.4/image.tar`
|
||||
- Run container with a volume mount and verify /api/health responds
|
||||
- Test yt-dlp download of a known video
|
||||
- Test Gemini API transcription
|
||||
- Test OAuth flow
|
||||
- Test subscription check
|
||||
3. Package with start-sdk: `make -C start9/0.4 package`
|
||||
4. Sideload on StartOS and test end-to-end:
|
||||
- Install service
|
||||
- Set up Gemini API key via config
|
||||
- Run OAuth authentication
|
||||
- Process a YouTube video
|
||||
- Process a podcast episode
|
||||
- Test subscription auto-discovery
|
||||
- Test backup/restore
|
||||
5. Iterate on issues found
|
||||
|
||||
### Phase 4: Documentation and Polish (Estimated: 1 day)
|
||||
|
||||
1. Write comprehensive instructions.md for StartOS users
|
||||
2. Update DEPLOY.md with StartOS 0.4.0 specific steps
|
||||
3. Update START9_PACKAGING_LOG.md with the complete process
|
||||
4. Verify backup/restore works correctly
|
||||
5. Test yt-dlp auto-update from within the running service
|
||||
6. Document the config spec clearly
|
||||
|
||||
---
|
||||
|
||||
## 9. Persistent Data Contract
|
||||
|
||||
Everything under `/data` persists across container restarts and package upgrades:
|
||||
|
||||
```
|
||||
/data/
|
||||
history/ # All summary JSON files
|
||||
subscriptions.json # Channel/feed subscriptions
|
||||
_meta.json # Folder organization
|
||||
seen-list.json # Dedup tracking
|
||||
skip-list.json # Deleted item tracking
|
||||
auto-queue.json # Pending queue items
|
||||
*.json # Individual summary records
|
||||
config/
|
||||
startos-config.json # StartOS-managed configuration
|
||||
cookies.txt # YouTube cookie file (if uploaded)
|
||||
.env # Environment overrides (Gemini key, etc.)
|
||||
bin/
|
||||
yt-dlp # Updated yt-dlp binary (runtime-managed)
|
||||
ytdlp-cache/ # yt-dlp cache (OAuth tokens, etc.)
|
||||
```
|
||||
|
||||
**Migration contract:** Any future package version must preserve this layout. If the schema of JSON files changes, handle migration in the entrypoint script or a dedicated migration step.
|
||||
|
||||
---
|
||||
|
||||
## 10. Ongoing Maintenance Plan
|
||||
|
||||
### Regular Maintenance (Monthly)
|
||||
|
||||
- **Rebuild and push package** -- even if the app code hasn't changed, rebuilding picks up the latest Alpine packages, Node.js patches, and yt-dlp version at build time
|
||||
- **Check yt-dlp compatibility** -- verify that the runtime auto-update is working by checking the version via the health endpoint
|
||||
|
||||
### When YouTube Breaks Things
|
||||
|
||||
YouTube periodically makes changes that break yt-dlp. When this happens:
|
||||
|
||||
1. Users can trigger "Update yt-dlp" from StartOS Actions menu
|
||||
2. If the action doesn't fix it, rebuild and push a new package with the latest yt-dlp
|
||||
3. If yt-dlp itself hasn't released a fix yet, the nightly build channel may have it -- consider switching the auto-update to use `yt-dlp --update-to nightly` temporarily
|
||||
|
||||
### When StartOS Updates
|
||||
|
||||
- Test the package on new StartOS versions before they're widely deployed
|
||||
- The 0.4.0 beta may have breaking changes as it stabilizes; pin to specific beta versions during testing
|
||||
- Keep the wrapper repo and packaging log updated
|
||||
|
||||
### Gemini API Changes
|
||||
|
||||
- The app already handles model fallbacks (tries multiple models)
|
||||
- Google periodically deprecates Gemini model versions; update the model list in server/index.js when this happens
|
||||
- API key management is handled via StartOS config, so no package rebuild needed for key rotation
|
||||
|
||||
---
|
||||
|
||||
## 11. Risk Assessment
|
||||
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|---|---|---|---|
|
||||
| YouTube breaks yt-dlp | High (happens regularly) | Downloads fail until yt-dlp updates | Runtime auto-update + manual action button |
|
||||
| OAuth tokens expire | Medium | Need to re-authenticate | Clear UI instructions; cookies.txt as backup |
|
||||
| Gemini API changes/deprecates models | Low-Medium | Transcription fails | Model fallback chain already implemented |
|
||||
| StartOS 0.4.0 beta has breaking changes | Medium | Package may need rework | Stay on documented APIs; test frequently |
|
||||
| Docker image too large | Low | Slow install/update | Multi-stage build; Alpine base; minimize layers |
|
||||
| Container can't reach YouTube (network) | Low (home network) | Downloads fail | StartOS allows outbound; verify in LXC |
|
||||
| Temp audio files fill disk | Low | Processing fails | Cleanup in /tmp; use TMPDIR on volume if needed |
|
||||
| cookies.txt expires quickly | High (3-5 days) | Auth fails | OAuth2 as primary; clear messaging about cookie limits |
|
||||
|
||||
---
|
||||
|
||||
## 12. Multi-User Distribution: API Keys and Clean Installs
|
||||
|
||||
### Gemini API Key Management
|
||||
|
||||
The Gemini API key must never be baked into the Docker image or package. Each user provides their own key after installation.
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. The `.env` file (which contains your personal API key) is excluded from the Docker image via `.dockerignore`
|
||||
2. On fresh install, the service starts with no API key configured
|
||||
3. The user enters their key via the StartOS config UI, which writes it to `/data/config/startos-config.json` on the persistent volume
|
||||
4. The entrypoint script reads this file and sets `GEMINI_API_KEY` as an environment variable before starting the server
|
||||
5. The web UI settings panel also lets users enter/change the key at any time (this writes to the server's in-memory state and persists to the config file)
|
||||
|
||||
The app already supports this pattern: it reads `GEMINI_API_KEY` from the environment first, then falls back to the `.env` file. On StartOS the environment variable takes precedence, and the `.env` file simply doesn't exist in a fresh install.
|
||||
|
||||
### Clean Installs: No Inherited Data
|
||||
|
||||
The Docker image contains only application code -- no user data. Everything personal lives on the `/data` volume, which starts empty for every new install. This means:
|
||||
|
||||
- No inherited history (processed videos/podcasts)
|
||||
- No inherited subscriptions
|
||||
- No inherited cookies or authentication tokens
|
||||
- No inherited API keys
|
||||
- No inherited folder organization or skip/seen lists
|
||||
|
||||
**The `.dockerignore` ensures nothing personal leaks into the image:**
|
||||
|
||||
```
|
||||
history/
|
||||
cookies.txt
|
||||
.env
|
||||
*.s9pk
|
||||
image.tar
|
||||
node_modules/
|
||||
.DS_Store
|
||||
GET-STARTED.*
|
||||
build-guide-pdf.py
|
||||
create-app.sh
|
||||
setup.sh
|
||||
Start Summarizer.command
|
||||
start9/
|
||||
```
|
||||
|
||||
**First-run flow for a new user:**
|
||||
1. Install the package from StartOS
|
||||
2. Open service config, enter Gemini API key
|
||||
3. Open the web UI
|
||||
4. Set up YouTube OAuth authentication (one-time device code flow)
|
||||
5. Add subscriptions to channels/feeds they want to follow
|
||||
6. Start summarizing -- their library builds from scratch
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: File-by-File Packaging Checklist
|
||||
|
||||
When creating the StartOS package, create/modify these files:
|
||||
|
||||
**New files to create (in start9/0.4/):**
|
||||
|
||||
- [ ] `manifest.yaml` -- set id, title, version, interfaces, config spec, actions, backup
|
||||
- [ ] `Dockerfile` -- multi-stage build, Alpine, Node 20, Python, yt-dlp, ffmpeg
|
||||
- [ ] `docker_entrypoint.sh` -- data dir setup, yt-dlp path, env loading, server start
|
||||
- [ ] `healthcheck.sh` -- curl to /api/health
|
||||
- [ ] `Makefile` -- image-arm, package, verify, clean targets
|
||||
- [ ] `instructions.md` -- setup guide, OAuth instructions, cookie upload, troubleshooting
|
||||
- [ ] `DEPLOY.md` -- build + sideload steps for StartOS 0.4.0
|
||||
- [ ] `LICENSE` -- appropriate license file
|
||||
- [ ] `icon.png` -- app icon (already exists in assets/)
|
||||
|
||||
**App code modifications (in server/index.js):**
|
||||
|
||||
- [ ] Add DATA_DIR environment variable support for all file paths
|
||||
- [ ] Remove auto-sleep/heartbeat shutdown logic
|
||||
- [ ] Remove macOS-specific code (osascript, LAN mode, brew update strategy)
|
||||
- [ ] Add OAuth2 device flow endpoints
|
||||
- [ ] Add download rate limiting for auto-queue
|
||||
- [ ] Add --impersonate chrome flag to yt-dlp calls
|
||||
- [ ] Move cookies.txt path to DATA_DIR
|
||||
- [ ] Update yt-dlp update strategies for Linux container
|
||||
- [ ] Add proxy support (optional config)
|
||||
- [ ] Bind to 0.0.0.0 (currently does this via HOSTNAME env)
|
||||
|
||||
**Documentation updates:**
|
||||
|
||||
- [ ] START9_PACKAGING_LOG.md -- full process documentation (like workout-log)
|
||||
- [ ] VERSIONING.md -- update with youtube-summarizer version policy
|
||||
- [ ] 0.4/README.md -- migration notes and packaging intent
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: Reusable Packaging Roadmap for Future Apps
|
||||
|
||||
This section generalizes the process so it can be reused for packaging any app for StartOS.
|
||||
|
||||
### Step 1: Assess the App
|
||||
|
||||
Before packaging, answer these questions:
|
||||
1. What language/runtime does the app use? (Determines base Docker image)
|
||||
2. Does it need external binaries? (yt-dlp, ffmpeg, etc. -- add to Dockerfile)
|
||||
3. Does it need outbound network access? (API calls, downloads -- verify in StartOS)
|
||||
4. What is the persistent data? (Database, files, config -- maps to /data volume)
|
||||
5. Does it have a health endpoint? (Required for StartOS health checks)
|
||||
6. Does it need configuration? (Maps to StartOS config spec)
|
||||
7. Does it have any platform-specific code? (macOS, Windows -- must be removed/adapted)
|
||||
|
||||
### Step 2: Create the Wrapper
|
||||
|
||||
1. Copy the template from an existing wrapper (this project or workout-log)
|
||||
2. Edit manifest.yaml first -- it defines everything
|
||||
3. Write the Dockerfile -- multi-stage build, Alpine, minimal layers
|
||||
4. Write docker_entrypoint.sh -- data init, env setup, exec app
|
||||
5. Write healthcheck.sh -- simple curl to health endpoint
|
||||
6. Write instructions.md -- user-facing setup guide
|
||||
|
||||
### Step 3: Build and Test Locally
|
||||
|
||||
```bash
|
||||
# Build ARM64 image
|
||||
make -C start9/0.4 image-arm
|
||||
|
||||
# Load and test
|
||||
docker load -i start9/0.4/image.tar
|
||||
docker run -it --rm -v ./test-data:/data -p 3001:3001 <image-name>
|
||||
|
||||
# Verify health
|
||||
curl http://localhost:3001/api/health
|
||||
```
|
||||
|
||||
### Step 4: Package and Sideload
|
||||
|
||||
```bash
|
||||
# Must be in a git repo
|
||||
git init && git add . && git commit -m "Initial packaging"
|
||||
|
||||
# Build s9pk
|
||||
make -C start9/0.4 package
|
||||
|
||||
# Verify
|
||||
make -C start9/0.4 verify
|
||||
|
||||
# Sideload via StartOS web UI
|
||||
```
|
||||
|
||||
### Step 5: Document Everything
|
||||
|
||||
- Update START9_PACKAGING_LOG.md with the full process
|
||||
- Record all issues encountered and how they were resolved
|
||||
- Note any StartOS version-specific quirks
|
||||
- Keep the manifest and Dockerfile well-commented
|
||||
|
||||
### Template Variables for New Projects
|
||||
|
||||
| Variable | Description | Example |
|
||||
|---|---|---|
|
||||
| `<PKG_ID>` | StartOS package identifier | `youtube-summarizer` |
|
||||
| `<APP_PORT>` | Internal container port | `3001` |
|
||||
| `<DATA_PATH>` | Persistent volume mount | `/data` |
|
||||
| `<HEALTH_PATH>` | Health endpoint path | `/api/health` |
|
||||
| `<PROJECT_ROOT>` | Absolute path to repo | `/Users/macpro/Projects/youtube-summarizer` |
|
||||
|
||||
---
|
||||
|
||||
*This document should be updated as the implementation progresses. Each phase completed should be annotated with actual outcomes, issues discovered, and any deviations from the plan.*
|
||||
Executable
+91
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# YouTube Summarizer — Double-click this file to launch!
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
# Move to the folder where this script lives (the project folder)
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
clear
|
||||
echo "============================================"
|
||||
echo " YouTube Summarizer — Starting up..."
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
# ── Check for Node.js ────────────────────────────────────────
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo "ERROR: Node.js is not installed."
|
||||
echo ""
|
||||
echo "To install it, open Terminal and run:"
|
||||
echo " brew install node"
|
||||
echo ""
|
||||
echo "(If you don't have Homebrew, install it first:"
|
||||
echo " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
||||
echo ")"
|
||||
echo ""
|
||||
echo "Press any key to close..."
|
||||
read -n 1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Check for yt-dlp ─────────────────────────────────────────
|
||||
if ! command -v yt-dlp &> /dev/null; then
|
||||
echo "yt-dlp not found. Installing via Homebrew..."
|
||||
if command -v brew &> /dev/null; then
|
||||
brew install yt-dlp
|
||||
else
|
||||
echo "ERROR: yt-dlp is not installed and Homebrew is not available."
|
||||
echo "Install yt-dlp manually: https://github.com/yt-dlp/yt-dlp"
|
||||
echo ""
|
||||
echo "Press any key to close..."
|
||||
read -n 1
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Install npm dependencies if needed ───────────────────────
|
||||
if [ ! -d "server/node_modules" ]; then
|
||||
echo "First run — installing dependencies..."
|
||||
cd server
|
||||
npm install
|
||||
cd ..
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ── Start the server ─────────────────────────────────────────
|
||||
echo "Starting server..."
|
||||
echo ""
|
||||
|
||||
# Start server in the background
|
||||
cd server
|
||||
node index.js &
|
||||
SERVER_PID=$!
|
||||
cd ..
|
||||
|
||||
# Wait for server to be ready
|
||||
echo "Waiting for server to start..."
|
||||
for i in {1..20}; do
|
||||
if curl -s http://localhost:3001/api/health > /dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
# ── Open browser ─────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "Opening browser..."
|
||||
open http://localhost:3001
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " App is running at http://localhost:3001"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Leave this window open while using the app."
|
||||
echo "To stop the server, close this window or press Ctrl+C."
|
||||
echo ""
|
||||
|
||||
# Keep the script running so the server stays alive
|
||||
# When user closes the terminal window or presses Ctrl+C, clean up
|
||||
trap "echo ''; echo 'Shutting down server...'; kill $SERVER_PID 2>/dev/null; exit 0" INT TERM
|
||||
|
||||
wait $SERVER_PID
|
||||
@@ -0,0 +1,18 @@
|
||||
# YouTube Summarizer
|
||||
|
||||
Download, transcribe, and summarize YouTube videos and podcast episodes using Google Gemini AI.
|
||||
|
||||
## Features
|
||||
|
||||
- Paste any YouTube URL or podcast RSS feed to get a full transcript with timestamps
|
||||
- AI-powered topic segmentation and summaries
|
||||
- Channel and podcast subscriptions with automatic new episode detection
|
||||
- Background processing queue with configurable delays
|
||||
- Auto-download toggle per subscription
|
||||
- Organized history with folders and search
|
||||
- Multiple Gemini model support
|
||||
- OAuth2 YouTube authentication for reliable downloads
|
||||
|
||||
## Requirements
|
||||
|
||||
- A Google Gemini API key (free tier available at [aistudio.google.com/apikey](https://aistudio.google.com/apikey))
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,326 @@
|
||||
from reportlab.lib.pagesizes import letter
|
||||
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||
from reportlab.lib.colors import HexColor
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.enums import TA_LEFT, TA_CENTER
|
||||
from reportlab.platypus import (
|
||||
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
|
||||
PageBreak, KeepTogether, HRFlowable, Preformatted
|
||||
)
|
||||
from reportlab.lib import colors
|
||||
import os
|
||||
|
||||
OUTPUT = os.path.join(os.path.dirname(__file__), "GET-STARTED.pdf")
|
||||
|
||||
doc = SimpleDocTemplate(
|
||||
OUTPUT,
|
||||
pagesize=letter,
|
||||
topMargin=0.75 * inch,
|
||||
bottomMargin=0.75 * inch,
|
||||
leftMargin=0.85 * inch,
|
||||
rightMargin=0.85 * inch,
|
||||
)
|
||||
|
||||
styles = getSampleStyleSheet()
|
||||
|
||||
# Custom styles
|
||||
styles.add(ParagraphStyle(
|
||||
"DocTitle", parent=styles["Title"],
|
||||
fontSize=26, leading=32, textColor=HexColor("#0f172a"),
|
||||
spaceAfter=4, fontName="Helvetica-Bold",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"DocSubtitle", parent=styles["Normal"],
|
||||
fontSize=13, leading=18, textColor=HexColor("#64748b"),
|
||||
spaceAfter=24, alignment=TA_CENTER,
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"H1", parent=styles["Heading1"],
|
||||
fontSize=20, leading=26, textColor=HexColor("#0f172a"),
|
||||
spaceBefore=28, spaceAfter=10, fontName="Helvetica-Bold",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"H2", parent=styles["Heading2"],
|
||||
fontSize=15, leading=20, textColor=HexColor("#1e293b"),
|
||||
spaceBefore=20, spaceAfter=8, fontName="Helvetica-Bold",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"Body", parent=styles["Normal"],
|
||||
fontSize=11, leading=17, textColor=HexColor("#334155"),
|
||||
spaceAfter=8, fontName="Helvetica",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"BodyBold", parent=styles["Normal"],
|
||||
fontSize=11, leading=17, textColor=HexColor("#1e293b"),
|
||||
spaceAfter=8, fontName="Helvetica-Bold",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"CodeBlock", parent=styles["Code"],
|
||||
fontSize=10, leading=14, textColor=HexColor("#1e293b"),
|
||||
backColor=HexColor("#f1f5f9"),
|
||||
fontName="Courier", leftIndent=16, rightIndent=16,
|
||||
spaceBefore=4, spaceAfter=8,
|
||||
borderPadding=(8, 8, 8, 8),
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"BulletItem", parent=styles["Normal"],
|
||||
fontSize=11, leading=17, textColor=HexColor("#334155"),
|
||||
leftIndent=24, bulletIndent=10, spaceAfter=4,
|
||||
fontName="Helvetica",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"StepNum", parent=styles["Normal"],
|
||||
fontSize=11, leading=17, textColor=HexColor("#334155"),
|
||||
leftIndent=24, bulletIndent=4, spaceAfter=4,
|
||||
fontName="Helvetica",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"Note", parent=styles["Normal"],
|
||||
fontSize=10, leading=15, textColor=HexColor("#92400e"),
|
||||
backColor=HexColor("#fffbeb"),
|
||||
leftIndent=12, rightIndent=12,
|
||||
spaceBefore=8, spaceAfter=8,
|
||||
borderPadding=(8, 8, 8, 8),
|
||||
fontName="Helvetica",
|
||||
))
|
||||
styles.add(ParagraphStyle(
|
||||
"Link", parent=styles["Normal"],
|
||||
fontSize=11, leading=17, textColor=HexColor("#2563eb"),
|
||||
spaceAfter=4, fontName="Helvetica",
|
||||
))
|
||||
|
||||
def code_block(text):
|
||||
"""Create a code block with background using Preformatted to preserve newlines."""
|
||||
return Preformatted(text, styles["CodeBlock"])
|
||||
|
||||
def hr():
|
||||
return HRFlowable(width="100%", thickness=1, color=HexColor("#e2e8f0"), spaceBefore=12, spaceAfter=12)
|
||||
|
||||
story = []
|
||||
|
||||
# -- Title --
|
||||
story.append(Spacer(1, 40))
|
||||
story.append(Paragraph("YouTube Transcript Summarizer", styles["DocTitle"]))
|
||||
story.append(Paragraph("Mac Setup Guide", styles["DocSubtitle"]))
|
||||
story.append(hr())
|
||||
|
||||
# -- What you're setting up --
|
||||
story.append(Paragraph("What You're Setting Up", styles["H1"]))
|
||||
story.append(Paragraph(
|
||||
"This app has two parts that work together:",
|
||||
styles["Body"]
|
||||
))
|
||||
story.append(Paragraph(
|
||||
"<b>1. A small server</b> that runs locally on your Mac (not on the internet -- only you can access it). "
|
||||
"It downloads YouTube audio and talks to Google's Gemini AI.",
|
||||
styles["BulletItem"]
|
||||
))
|
||||
story.append(Paragraph(
|
||||
"<b>2. A webpage</b> that the server hosts in your browser at <font face='Courier'>http://localhost:3001</font>.",
|
||||
styles["BulletItem"]
|
||||
))
|
||||
story.append(Spacer(1, 4))
|
||||
story.append(Paragraph(
|
||||
"Nothing is uploaded anywhere. Everything runs on your machine.",
|
||||
styles["BodyBold"]
|
||||
))
|
||||
|
||||
# -- Where to save --
|
||||
story.append(Paragraph("Where to Save the Project", styles["H1"]))
|
||||
story.append(Paragraph(
|
||||
"The <font face='Courier' color='#1e293b'>youtube-summarizer</font> folder you downloaded can live anywhere, "
|
||||
"but the standard Mac convention for projects like this is:",
|
||||
styles["Body"]
|
||||
))
|
||||
story.append(code_block("~/Projects/youtube-summarizer"))
|
||||
story.append(Paragraph(
|
||||
"The <font face='Courier'>~</font> means your home folder (e.g., <font face='Courier'>/Users/grant</font>). "
|
||||
"If you don't have a <font face='Courier'>Projects</font> folder yet, you'll create one below.",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
story.append(Paragraph("To move the files there:", styles["BodyBold"]))
|
||||
story.append(Paragraph("1. Open <b>Finder</b>", styles["StepNum"]))
|
||||
story.append(Paragraph("2. Go to your home folder (press <b>Cmd + Shift + H</b>)", styles["StepNum"]))
|
||||
story.append(Paragraph("3. Create a new folder called <b>Projects</b> if you don't have one", styles["StepNum"]))
|
||||
story.append(Paragraph("4. Drag the <font face='Courier'>youtube-summarizer</font> folder from your Cowork downloads into <b>Projects</b>", styles["StepNum"]))
|
||||
|
||||
story.append(Spacer(1, 8))
|
||||
story.append(Paragraph("You should end up with this structure:", styles["Body"]))
|
||||
story.append(code_block(
|
||||
"~/Projects/youtube-summarizer/\n"
|
||||
"|-- public/\n"
|
||||
"| +-- index.html\n"
|
||||
"|-- server/\n"
|
||||
"| |-- index.js\n"
|
||||
"| +-- package.json\n"
|
||||
"|-- setup.sh\n"
|
||||
"|-- Start Summarizer.command <-- double-click to launch!\n"
|
||||
"+-- GET-STARTED.pdf <-- this file"
|
||||
))
|
||||
|
||||
# -- Step 1 --
|
||||
story.append(PageBreak())
|
||||
story.append(Paragraph("Step 1: Install Node.js and yt-dlp", styles["H1"]))
|
||||
story.append(Paragraph(
|
||||
"You need two things installed: Node.js (runs the server) and yt-dlp (downloads YouTube audio). "
|
||||
"The easiest way to install both is with Homebrew.",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
story.append(Paragraph("If you don't have Homebrew yet:", styles["BodyBold"]))
|
||||
story.append(Paragraph("1. Open <b>Terminal</b> (press <b>Cmd + Space</b>, type \"Terminal\", hit Enter)", styles["StepNum"]))
|
||||
story.append(Paragraph("2. Paste this and press Enter:", styles["StepNum"]))
|
||||
story.append(code_block('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'))
|
||||
story.append(Paragraph("3. Follow the prompts (it may ask for your Mac password)", styles["StepNum"]))
|
||||
|
||||
story.append(Spacer(1, 8))
|
||||
story.append(Paragraph("Then install Node.js and yt-dlp:", styles["BodyBold"]))
|
||||
story.append(code_block("brew install node yt-dlp"))
|
||||
|
||||
story.append(Spacer(1, 4))
|
||||
story.append(Paragraph("Verify they're installed:", styles["Body"]))
|
||||
story.append(code_block("node --version\nyt-dlp --version"))
|
||||
story.append(Paragraph(
|
||||
"You should see version numbers for both. If so, you're ready for the next step.",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
# -- Step 2 --
|
||||
story.append(Paragraph("Step 2: Install Server Dependencies", styles["H1"]))
|
||||
story.append(Paragraph(
|
||||
"This is a one-time step. In Terminal, run:",
|
||||
styles["Body"]
|
||||
))
|
||||
story.append(code_block("cd ~/Projects/youtube-summarizer/server\nnpm install"))
|
||||
story.append(Paragraph(
|
||||
"This downloads the JavaScript libraries the server needs. You'll see some output scroll by -- "
|
||||
"when it finishes and shows you a new prompt, you're done.",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
# -- Step 3 --
|
||||
story.append(Paragraph("Step 3: Add Your Gemini API Key", styles["H1"]))
|
||||
story.append(Paragraph("The app needs a Google Gemini API key to transcribe and analyze videos.", styles["Body"]))
|
||||
|
||||
story.append(Spacer(1, 4))
|
||||
story.append(Paragraph("Get a free key:", styles["BodyBold"]))
|
||||
story.append(Paragraph("1. Go to <b><font color='#2563eb'>https://aistudio.google.com/apikey</font></b>", styles["StepNum"]))
|
||||
story.append(Paragraph("2. Sign in with your Google account", styles["StepNum"]))
|
||||
story.append(Paragraph("3. Click \"Create API Key\"", styles["StepNum"]))
|
||||
story.append(Paragraph("4. Copy the key -- you'll paste it in the app after launching", styles["StepNum"]))
|
||||
|
||||
# -- Step 4 --
|
||||
story.append(PageBreak())
|
||||
story.append(Paragraph("Step 4: Launch the App", styles["H1"]))
|
||||
story.append(Paragraph(
|
||||
"This is the fun part. You have two ways to launch:",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
story.append(Spacer(1, 4))
|
||||
story.append(Paragraph("Option A: Double-click (recommended)", styles["H2"]))
|
||||
story.append(Paragraph(
|
||||
"Find <font face='Courier'>Start Summarizer.command</font> in your project folder and double-click it.",
|
||||
styles["Body"]
|
||||
))
|
||||
story.append(Paragraph(
|
||||
"The first time, macOS may say the file can't be opened because it's from an unidentified developer. "
|
||||
"If this happens: right-click the file, choose <b>Open</b>, then click <b>Open</b> in the dialog. "
|
||||
"You only need to do this once.",
|
||||
styles["Note"]
|
||||
))
|
||||
story.append(Paragraph(
|
||||
"A Terminal window will open, the server will start, and your browser will automatically open to the app. "
|
||||
"That's it!",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
story.append(Spacer(1, 8))
|
||||
story.append(Paragraph("Option B: Terminal", styles["H2"]))
|
||||
story.append(Paragraph("If you prefer the command line:", styles["Body"]))
|
||||
story.append(code_block("cd ~/Projects/youtube-summarizer/server\nnpm start"))
|
||||
story.append(Paragraph(
|
||||
"Then open <b><font color='#2563eb'>http://localhost:3001</font></b> in your browser.",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
# -- Step 5 --
|
||||
story.append(Spacer(1, 8))
|
||||
story.append(Paragraph("Step 5: Summarize a Video", styles["H1"]))
|
||||
story.append(Paragraph("1. In the app, click <b>\"Gemini API Settings\"</b> and paste your API key", styles["StepNum"]))
|
||||
story.append(Paragraph("2. Paste a YouTube URL into the main input", styles["StepNum"]))
|
||||
story.append(Paragraph("3. Click <b>Summarize</b>", styles["StepNum"]))
|
||||
story.append(Paragraph("4. Watch the 3-step pipeline: Download audio -> Transcribe -> Analyze topics", styles["StepNum"]))
|
||||
story.append(Paragraph("5. Click any topic section to expand the full transcript with clickable timestamps", styles["StepNum"]))
|
||||
story.append(Spacer(1, 4))
|
||||
story.append(Paragraph(
|
||||
"Your API key is saved in your browser so you don't have to re-enter it each time.",
|
||||
styles["Body"]
|
||||
))
|
||||
|
||||
# -- Day-to-day --
|
||||
story.append(hr())
|
||||
story.append(Paragraph("Day-to-Day Usage", styles["H1"]))
|
||||
story.append(Paragraph(
|
||||
"After the one-time setup above, here's all you need to do each time:",
|
||||
styles["Body"]
|
||||
))
|
||||
story.append(Paragraph(
|
||||
"1. Double-click <font face='Courier'>Start Summarizer.command</font>",
|
||||
styles["StepNum"]
|
||||
))
|
||||
story.append(Paragraph(
|
||||
"2. Your browser opens automatically -- paste a YouTube link and go",
|
||||
styles["StepNum"]
|
||||
))
|
||||
story.append(Paragraph(
|
||||
"3. When done, close the Terminal window that opened (this stops the server)",
|
||||
styles["StepNum"]
|
||||
))
|
||||
story.append(Spacer(1, 4))
|
||||
story.append(Paragraph("That's it. One double-click.", styles["BodyBold"]))
|
||||
|
||||
# -- Troubleshooting --
|
||||
story.append(PageBreak())
|
||||
story.append(Paragraph("Troubleshooting", styles["H1"]))
|
||||
|
||||
troubles = [
|
||||
(
|
||||
"macOS won't open Start Summarizer.command",
|
||||
"Right-click the file, choose <b>Open</b>, then click <b>Open</b> in the security dialog. "
|
||||
"This only happens the first time."
|
||||
),
|
||||
(
|
||||
"\"Cannot connect to backend at localhost:3001\"",
|
||||
"The server isn't running. Double-click <font face='Courier'>Start Summarizer.command</font> again."
|
||||
),
|
||||
(
|
||||
"\"yt-dlp not installed\"",
|
||||
"Run <font face='Courier'>brew install yt-dlp</font> in Terminal, then relaunch the app."
|
||||
),
|
||||
(
|
||||
"Download fails or hangs",
|
||||
"yt-dlp might be outdated. Click the \"Update now\" button in the app, or run "
|
||||
"<font face='Courier'>brew upgrade yt-dlp</font> in Terminal."
|
||||
),
|
||||
(
|
||||
"\"Gemini API error: 403\" or \"401\"",
|
||||
"Your API key is invalid or expired. Get a new one from "
|
||||
"<font color='#2563eb'>https://aistudio.google.com/apikey</font>"
|
||||
),
|
||||
(
|
||||
"Long videos take a while",
|
||||
"Normal. A 1-hour video takes ~30 seconds to download, 30-60 seconds for Gemini "
|
||||
"to transcribe, then 10-20 seconds for topic analysis. The app shows live progress."
|
||||
),
|
||||
]
|
||||
|
||||
for problem, solution in troubles:
|
||||
story.append(Paragraph(f"<b>{problem}</b>", styles["BodyBold"]))
|
||||
story.append(Paragraph(solution, styles["BulletItem"]))
|
||||
story.append(Spacer(1, 6))
|
||||
|
||||
# Build
|
||||
doc.build(story)
|
||||
print(f"PDF created: {OUTPUT}")
|
||||
+838
@@ -0,0 +1,838 @@
|
||||
# Netscape HTTP Cookie File
|
||||
# This file is generated by yt-dlp. Do not edit.
|
||||
|
||||
www.recaptcha.net FALSE /recaptcha TRUE 1780180930 _GRECAPTCHA 09ADiQh0dtDEiRMi5WBdQDNRHouJD94ppMc5_pTy3zyVunQwBbEcKtw1XqCAXn_gkExDi4ugUhCOoddAB10vH5POM
|
||||
www.google.com FALSE /recaptcha TRUE 1781725220 _GRECAPTCHA 09ABCLyOG6cxagI3Cieygmf8CmIePx8g730YQnA8OgOrFiMW6on8sgc4c6cl3ZekVdq6dZNEKV3slW9ta33n5Z9iM
|
||||
secure.insightexpressai.com FALSE /adserver TRUE 1786504594 IgniteCookieSync true
|
||||
.google.com TRUE /verify TRUE 1789498633 SNID ALbZf37S4_CrH7J5UP4bphJFKXefW7V_AFkhVBncLQOAFISyal6NWxMB4che_ZQac_ZeJDJHUECJdI-UcqzC0PO5rYfTy9oILug
|
||||
.google.com TRUE / TRUE 1789570228 __Secure-ENID 28.SE=R2eukpRLgAoi_g94FwISFIyz_hrGkQy70QU-Qlld5sS9lrIQtgunjeL-JNU-z7HQl2yQJ0F6yqKfFzXlMoBWJicTsjN8GFNiyELINOi5vU9jtD7EwlOIxOxv71AkEzMFVbBaNq1zhDy7rfIDW9BtANnRn-pXkGN9CfeRQn4gdq1xBRNvuBWYoNqcnTYp5LhJwRdP65bdRw
|
||||
.google.com TRUE / TRUE 1786833884 __Secure-BUCKET COID
|
||||
.google.com TRUE / TRUE 1786833884 AEC AaJma5vPc7N0Rl8mb8fOV-a7JjrmXzK3VfwniJq_dBv23b_DaBVcU7x8zA
|
||||
.google.com TRUE / FALSE 1808253661 SID g.a0007whSQ2FTtN3oaH2z5zAUg7rUNnJXuBC-FtNcmf_q4VZxCH6I5yCVYxA-LmPOHRXLgQktwAACgYKASYSARMSFQHGX2MitoydJ2nBzhSIkt8ceGNDPRoVAUF8yKpvGQGXHR2ixssAhIZ7Tlhg0076
|
||||
.google.com TRUE / TRUE 1808253661 __Secure-1PSID g.a0007whSQ2FTtN3oaH2z5zAUg7rUNnJXuBC-FtNcmf_q4VZxCH6IIWYz6SgNFiNwCFav4fBlxgACgYKAZgSARMSFQHGX2MiUhFl0FoKqeIalNYwK9r2kRoVAUF8yKquv1J4_ggvLRhNHGom3rco0076
|
||||
.google.com TRUE / TRUE 1808253661 __Secure-3PSID g.a0007whSQ2FTtN3oaH2z5zAUg7rUNnJXuBC-FtNcmf_q4VZxCH6Ip1KVQpXe0-3wXj_r0kABhgACgYKAVESARMSFQHGX2MiaYklqIL3lhBMrkEcEBXS5RoVAUF8yKpcc98ulcMv04cCcRloUdNL0076
|
||||
.google.com TRUE / FALSE 1808253661 HSID AKxOhbOXvqjOJatr5
|
||||
.google.com TRUE / TRUE 1808253661 SSID A4lGYkDwWuxlWMvHl
|
||||
.google.com TRUE / FALSE 1808253661 APISID MdMQfFFo_4b0Cw2d/Au_xxzGsUXCUZnFia
|
||||
.google.com TRUE / TRUE 1808253661 SAPISID gAA5ERfoktTnNYkF/A7x17szT_7WqXM9A1
|
||||
.google.com TRUE / TRUE 1808253661 __Secure-1PAPISID gAA5ERfoktTnNYkF/A7x17szT_7WqXM9A1
|
||||
.google.com TRUE / TRUE 1808253661 __Secure-3PAPISID gAA5ERfoktTnNYkF/A7x17szT_7WqXM9A1
|
||||
.google.com TRUE / TRUE 1790880901 NID 530=VZck2xuPHmmWPJE5RehuzIMISpa_iDox0Zh3zpvPk65oDM9Ux4odkGSz1xvlgMD-hc02ehFEliXyGMl1od4-zm3pIl29SHANM8ScGoGvuhUIlkqdgXi2cjC7lpiFf0oMdulG9947fGvqPBUG4WvTqVhqvww7AZ2DGFlK77FUt6AOkfj2l6CtJowDJGcafmu6jE7pw6VACKnOg-X_W2WhjIcSh30wN6HtZCeF_pnwDrtuRjWkDjuhZU9sYSZeXDyPPa6lekXjzwgBegdVTb7aznOCXViTxJdWG8TOwfDhGAcB_RXi0fGeVzRfqQkS-o2UjLkZtWhy1ZPDb699vhn8rGEtYcO-5OhQaf9g8qUnRkJQrtSDZMMtGSdCLey4SQxe1q4uF5Sl9hdMWCk3cAk1pKtm3zjql140Jzb7MOQpgCvgz392qwqwZp05Zi2ZyrdDDol7UIppKQQgEGeT2Gh2d7XJlzU_zS21W1YWF8GvEc801uU_QJ_MGORyghk__TwLfpRsiMRzOCGmxULHQMZqKZum0CrIaW_JOJbBcLeXG3xvb-Sma8Ja7l20dQZN_Sq2J0wx-aZxdNr4mAsYV_a5FnvoosEL3XIGbFRk_eEskDKUDQTnX86ZWpTBpW2wMPQ2mcmRZtRQkeHNyLpM71g-62pB3TBR_XqYuDABI3_xdkJbWgu1TVk9t1-CRpUbxETp2UIes7xTJ7oiusmMOoxX1igZvRnmbQCwhnvOGUZBZ1Ha8c9Uo9orPmMV6N3TFodn9EZu9sqr2yN-2BYUeC3wIOcLNpkygQ
|
||||
.google.com TRUE / FALSE 1806605701 SIDCC AKEyXzXC7yJXWDKmUNJMRQiH3LhIdsJivlmcAdK81cOTLXy5Z8Pd_WSnHvMeeSK6a0o8yzop
|
||||
.google.com TRUE / TRUE 1806605701 __Secure-1PSIDCC AKEyXzVfeKdFV0eLw1OkaCBWbw09BtzNgRtQSbrpcfN41eZEdt5ELWZRWXhaFdXl3U9Jxlgl
|
||||
.google.com TRUE / TRUE 1806605701 __Secure-3PSIDCC AKEyXzXdf2ecDiT04OPnOxH3dHiwXB2bfOSCeHXlFcqz5hKZFHwPGkaeie0FfwqxzqwvwlaG
|
||||
.docsend.com TRUE /view TRUE 1787106781 dbx_js_analytics_id AABO4ekPMjJgWc5twV879ddvZiBCkhtzHwGoowWv5363VQ
|
||||
.docsend.com TRUE / TRUE 1787106780 _us_ eyJfcmFpbHMiOnsibWVzc2FnZSI6IkluWnBaWGRsWkNCa2IyTWkiLCJleHAiOm51bGwsInB1ciI6ImNvb2tpZS5fdXNfIn19--d99e89135b29409ec95f7b01021ec543a463b2ba
|
||||
.docsend.com TRUE / FALSE 1787106781 _ga GA1.2.1299589222.1752546781
|
||||
.docsend.com TRUE / FALSE 1787106782 _ga_JPP8SP2PRX GS2.2.s1752546781$o1$g0$t1752546781$j60$l0$h0
|
||||
.docsend.com TRUE / FALSE 1775876784 intercom-id-lv6lji7h e901f578-bb42-4566-8776-a2dcc3939b1b
|
||||
.docsend.com TRUE / FALSE 1775876784 intercom-device-id-lv6lji7h 87e6f252-90d0-47b2-ab31-55527932921e
|
||||
.docsend.com TRUE / TRUE 1784082794 _v_ k%2BzmVODjr1ktn34Oy5Rj6FwijPhjhBGpWkI33sJ7Bj%2FtpHLVf6p0Taeaxid5jg2zt2mSMii9qw3DrLaqZsBZh1%2Bp8yO%2Fr4j%2Bjm5MHWpwCTM2RlbJ6aj8Sac%3D--l%2FPezHhegs%2Fdy9SM--lGHFKSAFr8z2NZdmHX6FoQ%3D%3D
|
||||
.liadm.com TRUE /j TRUE 1786540591 lidid b18b6947-1c7c-4b46-a344-36c6d4477e91
|
||||
.liadm.com TRUE / TRUE 1802646478 lidid b18b6947-1c7c-4b46-a344-36c6d4477e91
|
||||
.linkedin.com TRUE / TRUE 1799622470 bcookie "v=2&78faccf5-3ecd-4d84-8ab6-ef64a3bf747f"
|
||||
.linkedin.com TRUE / TRUE 1781649297 dfpfpt c83f1ecbd1d74f289955365b5826d8af
|
||||
.linkedin.com TRUE / FALSE 1783050085 sdui_ver sdui-flagship:0.1.7528+sdui-flagship.production
|
||||
.linkedin.com TRUE / TRUE 1790346598 liap true
|
||||
.linkedin.com TRUE / TRUE 1775862470 li_sugr 862c6d25-b5fa-45b5-91de-e013e23d12d0
|
||||
m.stripe.com FALSE / TRUE 1808408907 m 0d856586-3227-461d-a492-2fcbb6769537f33d44
|
||||
.bing.com TRUE / TRUE 1799780686 MUID 10188FE1CFA1634236249C51CE0F62C0
|
||||
.bing.com TRUE / TRUE 1785793502 MSPTC fytp5YpA8Dgp5mtmxchMYfBi46F4ajq3Odc1dbWzvvo
|
||||
.amazon-adsystem.com TRUE / TRUE 1802646478 ad-privacy 0
|
||||
.amazon-adsystem.com TRUE / TRUE 1790896078 ad-id A-mXDgT1iEQ0urAU5Uzkr5k
|
||||
.adsrvr.org TRUE / TRUE 1799622478 TDID 248c815d-b156-4db9-8a92-46c25764dd54
|
||||
.adsrvr.org TRUE / TRUE 1799622478 TDCPM CAESFwoIYXBwbmV4dXMSCwi0sdS11svYPhAFEhkKCnJpZ2h0bWVkaWESCwj6qYye-4rOPBAFEhUKBmdvb2dsZRILCKCmnrXWy9g-EAUSFgoHcnViaWNvbhILCNqij57jqeg-EAUSFQoGY2FzYWxlEgsIoIP2xoaAuz4QBRIXCghwdWJtYXRpYxILCIrZ9saGgLs-EAUSGAoJYmlkc3dpdGNoEgsIlvvKhOSp6D4QBRIUCgV0YXBhZBILCMrOs6Djqeg-EAUSGAoJbW9va2llLXBzEgsI1PONyPeu3j0QBRIbCgxzaGFyZXRocm91Z2gSCwiKgMj2hcDePRAFEhYKB3N2eDl0NTASCwjq7-aI5KnoPhAFEhcKCGxpdmVyYW1wEgsIkoa1_eOp6D4QBRIWCgdibHVla2FpEgsI-Ja-hefv7DwQBRIYCglhZGFkdmlzb3ISCwj2r_mG-a7ePRAFEhkKCmxpdmVpbnRlbnQSCwiamKPt0JzfPhAFEhYKB3lqbjBndXASCwjykoq_1svYPhAFEhYKB3NlbWFzaW8SCwjc-Lq-46noPhAFEhYKB2QwdHJvMWoSCwj6htye35HmPRAFEhIKA2FhbRILCNbqvIfAw5M-EAUSFgoHbGh3Yms1ORILCMqbh8f89Z4-EAUSFgoHYWRkdGhpcxILCKzKgoqB9p4-EAUYASABKAIyCwjA5um1-qnoPhAFOAFaB3N2eDl0NTBgAg..
|
||||
.tiktok.com TRUE / TRUE 1799780762 _ttp 2X2TZqZx4A6Bvfb8BIaqfx9Z0a3
|
||||
.everesttech.net TRUE / TRUE 1799622471 everest_g_v2 g_surferid~ZTLFuQAAMEMNAAAm
|
||||
.casalemedia.com TRUE / TRUE 1799622478 CMID ZTLFuNNR.cMSZsiLqmTKvgAA
|
||||
.casalemedia.com TRUE / TRUE 1775862478 CMPRO 1585
|
||||
.casalemedia.com TRUE / TRUE 1799622514 receive-cookie-deprecation 1
|
||||
.bidswitch.net TRUE / TRUE 1797620686 tuuid 7b3a0d56-9687-4b59-b959-b7bc82b68d2a
|
||||
.bidswitch.net TRUE / TRUE 1797620686 tuuid_lu 1766084685
|
||||
.mookie1.com TRUE / TRUE 1802214470 id 10595069975717265745
|
||||
.mookie1.com TRUE / TRUE 1802214470 mdata 1|10595069975717265745|1697826233608
|
||||
.mookie1.com TRUE / TRUE 1802214470 ov e128077993a710de39333b74744f58cb
|
||||
.scorecardresearch.com TRUE / TRUE 1801782478 UID 10E8f6bc100d2f5646935961697826233
|
||||
.scorecardresearch.com TRUE / TRUE 1801782478 XID 10E8f6bc100d2f5646935961697826233
|
||||
.openx.net TRUE / TRUE 1799622478 i 3ceaaa71-5ebd-457b-b49c-3cae42bce526|1697826233
|
||||
.openx.net TRUE / TRUE 1783481370 receive-cookie-deprecation 1
|
||||
.kargo.com TRUE / TRUE 1799622478 ktcid 6e219f4f-0df5-0bff-52c2-a571328f2277
|
||||
.pinterest.com TRUE / TRUE 1797620838 ar_debug 1
|
||||
.semasio.net TRUE / TRUE 1799622471 SEUNCY CAFD648EEF8CF9CB
|
||||
.taboola.com TRUE / TRUE 1799622477 t_gid f2df2eab-3a6c-44ab-a01a-6a5636142726-tuctc2c4b3a
|
||||
.taboola.com TRUE / TRUE 1799622477 t_pt_gid f2df2eab-3a6c-44ab-a01a-6a5636142726-tuctc2c4b3a
|
||||
.pubmatic.com TRUE / TRUE 1799622478 KADUSERCOOKIE 7EA55DAD-5ED1-42DD-AFF7-96B0187E2FE8
|
||||
.pubmatic.com TRUE / TRUE 1775862467 KRTBCOOKIE_153 19420-e4Ku6SuEpe9gja67eIW67HrTpLtgja64eNO-SLLc&KRTB&22979-e4Ku6SuEpe9gja67eIW67HrTpLtgja64eNO-SLLc&KRTB&23462-e4Ku6SuEpe9gja67eIW67HrTpLtgja64eNO-SLLc&KRTB&23661-e4Ku6SuEpe9gja67eIW67HrTpLtgja64eNO-SLLc
|
||||
.pubmatic.com TRUE / TRUE 1775862467 KRTBCOOKIE_80 16514-CAESEIBxL5SQt0wXrkALugcFNF8&KRTB&22987-CAESEIBxL5SQt0wXrkALugcFNF8&KRTB&23025-CAESEIBxL5SQt0wXrkALugcFNF8&KRTB&23386-CAESEIBxL5SQt0wXrkALugcFNF8
|
||||
.pubmatic.com TRUE / TRUE 1775862467 KRTBCOOKIE_740 23053-654168E218FD9BEFFD4A78C3BLIS&KRTB&23460-654168E218FD9BEFFD4A78C3BLIS&KRTB&23518-654168E218FD9BEFFD4A78C3BLIS&KRTB&23654-654168E218FD9BEFFD4A78C3BLIS
|
||||
.pubmatic.com TRUE / TRUE 1775862467 KRTBCOOKIE_188 3189-bad985e7-8794-4157-b22d-37333612913c-654168d8-5553&KRTB&23418-bad985e7-8794-4157-b22d-37333612913c-654168d8-5553&KRTB&23634-bad985e7-8794-4157-b22d-37333612913c-654168d8-5553
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_57 22776-1446664633062455738&KRTB&23339-1446664633062455738
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_466 16530-7b3a0d56-9687-4b59-b959-b7bc82b68d2a&KRTB&23280-7b3a0d56-9687-4b59-b959-b7bc82b68d2a
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_32 11175-AQALN3bf5gd9IQFydVqNAQEBAQEBAQEBAQEBAQEBAJqrK3NY&KRTB&22715-AQALN3bf5gd9IQFydVqNAQEBAQEBAQEBAQEBAQEBAJqrK3NY&KRTB&23519-AQALN3bf5gd9IQFydVqNAQEBAQEBAQEBAQEBAQEBAJqrK3NY&KRTB&23632-AQALN3bf5gd9IQFydVqNAQEBAQEBAQEBAQEBAQEBAJqrK3NY
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_377 6810-248c815d-b156-4db9-8a92-46c25764dd54&KRTB&22918-248c815d-b156-4db9-8a92-46c25764dd54&KRTB&22926-248c815d-b156-4db9-8a92-46c25764dd54&KRTB&23031-248c815d-b156-4db9-8a92-46c25764dd54
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_860 16335-Rinil22qUYFi4TknhSNdb2vCVQw&KRTB&23334-Rinil22qUYFi4TknhSNdb2vCVQw&KRTB&23417-Rinil22qUYFi4TknhSNdb2vCVQw&KRTB&23426-Rinil22qUYFi4TknhSNdb2vCVQw
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_1278 23329-0925f90d-eabf-4ced-b2b9-cadb9694d5e0&KRTB&23498-0925f90d-eabf-4ced-b2b9-cadb9694d5e0
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_1251 23269-di_deeb83f6ca8243feb00ca&KRTB&23571-di_deeb83f6ca8243feb00ca&KRTB&23677-di_deeb83f6ca8243feb00ca
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_1003 22761-4e497f88-782f-11ee-81f8-32482e403c1e&KRTB&23275-4e497f88-782f-11ee-81f8-32482e403c1e
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_964 20918-cuid_bb00f223-da8d-11ef-a301-12328e819285&KRTB&23354-cuid_bb00f223-da8d-11ef-a301-12328e819285&KRTB&23415-cuid_bb00f223-da8d-11ef-a301-12328e819285&KRTB&23422-cuid_bb00f223-da8d-11ef-a301-12328e819285
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_18 22947-970314644980085599&KRTB&23796-970314644980085599
|
||||
.pubmatic.com TRUE / TRUE 1775862468 KRTBCOOKIE_218 22978-ZTLFuQAAMEMNAAAm&KRTB&23194-ZTLFuQAAMEMNAAAm&KRTB&23209-ZTLFuQAAMEMNAAAm&KRTB&23244-ZTLFuQAAMEMNAAAm
|
||||
.pubmatic.com TRUE / TRUE 1775862469 SyncRTB4 1769212800%3A81_201_46_234_283_176_238_48_266_7_13_278_166_220_165_231_71_8_196_286_203_56_275_178_240_272_279_22_233_281_250_96_249_214_99_161_282_3_104_55_271_285_21_267_264_54%7C1768608000%3A2_15_223%7C1769299200%3A268%7C1770595200%3A224_273%7C1768435200%3A216%7C1768867200%3A63%7C1773187200%3A69
|
||||
.pubmatic.com TRUE / TRUE 1775862469 KRTBCOOKIE_1469 23583-7fafe40b-12f1-414e-b944-2666315f73d5
|
||||
.pubmatic.com TRUE / TRUE 1775862469 KRTBCOOKIE_945 19558-83bc6354-0805-4310-befc-80a97066c1a2
|
||||
.pubmatic.com TRUE / TRUE 1775862469 KRTBCOOKIE_1513 23789-o08rOa33HNvb&KRTB&23793-o08rOa33HNvb
|
||||
.pubmatic.com TRUE / TRUE 1775862469 KRTBCOOKIE_469 8273-847260793351&KRTB&23428-847260793351
|
||||
.pubmatic.com TRUE / TRUE 1775862469 KRTBCOOKIE_1199 23168-000011CF9CE959F2&KRTB&23175-000011CF9CE959F2
|
||||
.pubmatic.com TRUE / TRUE 1775862469 KRTBCOOKIE_1465 23572-A6781448135364746810
|
||||
.pubmatic.com TRUE / TRUE 1775862469 KRTBCOOKIE_27 16735-uid:66516793-f126-4800-87d3-3aaaac9ea049
|
||||
.pubmatic.com TRUE / TRUE 1775862470 KRTBCOOKIE_1515 23794-6962dbc575e323aa0d79326e&KRTB&23804-6962dbc575e323aa0d79326e
|
||||
.pubmatic.com TRUE / TRUE 1775862470 KRTBCOOKIE_594 17105-RX-f60793b1-0eef-4ca4-82c5-ee8a3b5cdab9-005&KRTB&17107-RX-f60793b1-0eef-4ca4-82c5-ee8a3b5cdab9-005
|
||||
.pubmatic.com TRUE / TRUE 1775862470 DPSync4 1769212800%3A228_245_197_219_226%7C1768089600%3A248%7C1770595200%3A102%7C1768608000%3A164_252
|
||||
.pubmatic.com TRUE / TRUE 1775862470 KRTBCOOKIE_699 22727-AADBck7KgtEAABjN509uAw&KRTB&22744-AADBck7KgtEAABjN509uAw&KRTB&23649-AADBck7KgtEAABjN509uAw
|
||||
.pubmatic.com TRUE / TRUE 1775862478 chkChromeAb67Sec 23
|
||||
.intentiq.com TRUE / TRUE 1802646477 IQver 1.9
|
||||
.intentiq.com TRUE / TRUE 1802646477 intentIQ 8YNjKdno5A
|
||||
.intentiq.com TRUE / TRUE 1802646477 IQadv 1704742284384
|
||||
.intentiq.com TRUE / TRUE 1802646477 IQPData 1807897868#1768086477519#0#1698785399818
|
||||
.zemanta.com TRUE / TRUE 1775862477 zuid B_w-bBKJ2SQ1pcXG69r3
|
||||
.bidr.io TRUE / TRUE 1802196478 bito AADBck7KgtEAABjN509uAw
|
||||
.targeting.unrulymedia.com TRUE / TRUE 1799622478 _rxuuid %7B%22rx_uuid%22%3A%22RX-f60793b1-0eef-4ca4-82c5-ee8a3b5cdab9-005%22%7D
|
||||
.lijit.com TRUE / TRUE 1799622493 ljt_reader HlHCURZHmnGY_htwRy2qdS7X
|
||||
.lijit.com TRUE / TRUE 1783480663 _ljtrtb_80 M6CF4TG8-W-J70S
|
||||
.lijit.com TRUE / TRUE 1783480566 _ljtrtb_58 7EA55DAD-5ED1-42DD-AFF7-96B0187E2FE8
|
||||
.lijit.com TRUE / TRUE 1783480583 _ljtrtb_5039 2YGMLNgKe4pU8mA41f8wMksvXS_5pk97WTqA5qysrKa8
|
||||
.lijit.com TRUE / TRUE 1783480589 _ljtrtb_27 248c815d-b156-4db9-8a92-46c25764dd54
|
||||
.lijit.com TRUE / TRUE 1783480589 _ljtrtb_85 AADBck7KgtEAABjN509uAw
|
||||
.lijit.com TRUE / TRUE 1783480606 _ljtrtb_1 7289271102826593249
|
||||
.lijit.com TRUE / TRUE 1796162270 ljtrtb eJyNVFtTGzsM%2Fi95rmYsW7LlM9OHzYXQBtIzhRLgpWN7vdxDSqAUzpz%2FfuTt%2BQHdh2TXkqzvIvufifeTvyZCwXoTonOMkw8TQbS6ymy8N9ETYrToMZLG2BjUmCtDrBoQiSI5RptqRUbjkHS14pjpg2ZqpQ1IwRkbnTGRnMZs6xqyS6ZnD9FLAMocIcf2E3IRm730NrXccReSIsg9ZNQC6nMESdEC%2BWI5eOp7bugoau7mltNhmbndLxcbG8NGVy%2BX1M02m%2FI8XXT6fJqevG27148fR6TY8Ix%2FHyaxcQ%2FE1vtoHGEQZ4P%2Fn7xrDezF8vhofbWqtPsmDx3hIK%2FHd%2Fuf5yffeXcXw%2Bb0R8c%2F3vZPqyRaFZpgYdExz7s58GKOQHY%2Bh%2B7gICj3qUEJC3uwaLmxkf16DsNoR0YwtQ5AJRGILQy1SnKZS59UAWO4bT866JJQrgLYSwUygpDioErZariqO1FGLXB0Ty7Wt6t%2B%2B8jdb%2FY4%2BkRRLTPkg3ocxQYjzSpGbPJRdOquc955MjEGltFj%2BXNqo8Y59VG4BpAQCQg5QLa2Bxfa3mgjugKeCdV9AWZuEEb9rESdIzRWrOfoLDU%2BzSpjvevMYopmbohNEKSDmXGexbGfhSaRVjXWo6iMMNjsgCUx5BQiBBfLEEqp3Jcx2Wnyl7%2B%2F6UBKJQrDQJn0EUquclZfSuirDpXy10yUvL9%2BogcfZP80zmtkRxp4SeD70LRM2tJYcM4OkFK1kLLPeSi2IOax5Th%2FFENg36qtGPF%2BPCrS1D%2F2swM6XQps4HMwJ2NJk55yYe6HjEPLbLiP1hfnm0%2FdDHAJdnU6HwGpGOMh%2Bv2imQ3e5eWv9c0Nzfbrp%2FXh9UDDz9OyvH68a%2FHGq%2Bvm03IXVlfPemCmt2s28aV7bdEGtrdfFg9nu0MXrzbd%2BxscpbCVsz3Oytft7eH6Md7wLJ%2FCanvWvKem%2F2D7wdaUwSVfgEjfkkEVKbFOFZLVSwieX8qz6kJ6N7RWDTZXCsYNBEjVALHLENV0iD3FYr3UbBopavTD%2B02fjwTuH56MIoYwh8%2Bp8u7%2BPbTvGJb3ac56P%2F37HxcjMs8%3D
|
||||
.lijit.com TRUE / TRUE 1783480662 _ljtrtb_76 83a84be8-1d8e-4081-a9f6-42e05e2ae989
|
||||
.lijit.com TRUE / TRUE 1796162270 _ljtrtb_5 18bshr4m678sr
|
||||
.lijit.com TRUE / TRUE 1799622478 ljtrtbexp eJxlkDkSQzEIQ%2B%2Fi2gWLWZSrZXL3b3tcfJMS9ECCb3NvHw5NWGpEb%2FIqtbfgVTsETkuOg6uprRpAbCI5JE8nz440JfSWdFtwsUy9PXIU3YpeI9f5nYiQYkEydT8JJ7D5KDfIvQ%2FbnxgugTmPKPmpPIlJK%2BF3pPEHZGlwefRAAURuwPJ91e8B2LtbPQ%3D%3D
|
||||
.lijit.com TRUE / TRUE 1799622493 3pids "8014:a7bfe61c1f5205b22e34465d03fefacb,,7d5b04e46ff8eaf91bec603bdbc20bba1fa3b4fa,,139c2033b0bb853ae6140cbd2ca1f01d680097a946f9a07139d46987737158b8,,|8100:b734715e576a5b620291c43f3b5a280f,,d97ab4c28d7a42897d04af42610829b0567be6ea,,1b042a61a1412bc36bc3d3631335628355f71e35c3a1ab246d663baa06c947d3,,|8110:a7bfe61c1f5205b22e34465d03fefacb,,7d5b04e46ff8eaf91bec603bdbc20bba1fa3b4fa,,139c2033b0bb853ae6140cbd2ca1f01d680097a946f9a07139d46987737158b8,,|8111:a7bfe61c1f5205b22e34465d03fefacb,,7d5b04e46ff8eaf91bec603bdbc20bba1fa3b4fa,,139c2033b0bb853ae6140cbd2ca1f01d680097a946f9a07139d46987737158b8,,|8105:a7bfe61c1f5205b22e34465d03fefacb,,7d5b04e46ff8eaf91bec603bdbc20bba1fa3b4fa,,139c2033b0bb853ae6140cbd2ca1f01d680097a946f9a07139d46987737158b8,,|8109:a7bfe61c1f5205b22e34465d03fefacb,,7d5b04e46ff8eaf91bec603bdbc20bba1fa3b4fa,,139c2033b0bb853ae6140cbd2ca1f01d680097a946f9a07139d46987737158b8,,"
|
||||
.ad.gt TRUE / TRUE 1783480661 au_id AU1D-0100-001698785414-LEW7MJH6-AH72
|
||||
.colossusssp.com TRUE / TRUE 1799622477 gtm_usr e0e12f89-8f68-4849-ae67-396e3605f5b6
|
||||
.colossusssp.com TRUE / TRUE 1799622477 lmg_r 66|15|3|10|12|76|11|67|77|101|97
|
||||
.sitescout.com TRUE / TRUE 1799622478 ssi bad985e7-8794-4157-b22d-37333612913c#1698785496290
|
||||
.blismedia.com TRUE / TRUE 1799626467 b 654168E218FD9BEFFD4A78C3BLIS
|
||||
.deepintent.com TRUE / TRUE 1802646478 CDIUSER di_deeb83f6ca8243feb00ca
|
||||
.deepintent.com TRUE / TRUE 1802646478 CDIPARTNERS %7B%221%22%3A%2220231031%22%2C%22129%22%3A%2220250124%22%2C%22131%22%3A%2220240410%22%2C%22132%22%3A%2220260110%22%2C%22136%22%3A%2220240222%22%2C%22108%22%3A%2220260110%22%2C%22140%22%3A%2220250708%22%2C%22141%22%3A%2220260110%22%2C%22142%22%3A%2220260110%22%2C%22143%22%3A%2220250708%22%2C%22112%22%3A%2220240222%22%2C%22113%22%3A%2220240109%22%2C%22145%22%3A%2220250125%22%2C%22114%22%3A%2220240222%22%2C%22146%22%3A%2220250124%22%2C%22147%22%3A%2220250708%22%2C%22149%22%3A%2220260110%22%2C%22150%22%3A%2220250708%22%2C%22152%22%3A%2220240410%22%2C%22121%22%3A%2220240410%22%2C%22122%22%3A%2220250124%22%2C%22126%22%3A%2220250124%22%7D
|
||||
.adgrx.com TRUE / TRUE 1802214468 ADGRX_UID 4e497f88-782f-11ee-81f8-32482e403c1e
|
||||
.rfihub.com TRUE / TRUE 1801782477 rud H4sIAAAAAAAA_-MSsjQ3MDY0MTMxsbQwMLAwNbW0FOIz1HX1yLTwC_dy9c33NwAABPBq-iQAAAA
|
||||
.rfihub.com TRUE / TRUE 1801782477 eud H4sIAAAAAAAA_1WPMU4DQQxFhUSFRIEikYYrDPKM7W-bDlBEA4KARL8hm46CFMA5KCkpU1JyhByBknKPQMWuCNkguXn297O8c5BPj0c3o5P7i3R1dn45f7ydz54g-vA89fH1bjYOpizMQrTY6thMQi1c6b1jODkELmIfHWsOEYUq5-U6D80iaNZzoCjR92a-sC22e1-Q0GfPZiz42lv53CIs42Vg9bTUDK7SrJ5YEvBdClIkj1p9UlVtx45WS07lUAMwxevg12Stpa3y9p-52e8vE5Eshxufumgz_PvMPILLDxiDv-1HAQAA
|
||||
.w55c.net TRUE / TRUE 1802300871 wfivefivec mVLEl9il1QXWCd5
|
||||
beacon.lynx.cognitivlabs.com FALSE / TRUE 1799622468 UID 0925f90d-eabf-4ced-b2b9-cadb9694d5e0
|
||||
beacon.lynx.cognitivlabs.com FALSE / TRUE 1799622468 ss 9ASfGcUg1Z%2FWeHvjiO8JiUrpDlWrXPsyV9c83nESnysaEoqoq3htALWD05NYmBxwcGQ8dvArMuP%2FrUwUteqA4ou6MJfDvjloGeeNrp1hxgU%3D
|
||||
.acuityplatform.com TRUE / TRUE 1799622477 auid 847260793351
|
||||
.acuityplatform.com TRUE / TRUE 1799622477 aum OikKAfqbdXNlck1hdGNoQnlVc2VyTWF0Y2hpbmdJZE1hcPqANvqNdXNlck1hdGNoaW5nSWTMkWxhc3REcm9wVGltZU1pbGxpcyUBTWpFJ1W8mGxhc3RTdWNjZXNzZnVsTWF0Y2hNaWxsaXMlAU1qRSdVvI90aGlyZFBhcnR5VXNlcklkIfuANPpCyEMlAUlDDkRIuEQlAUlDDkRIuEVaQ0FFU0VPbzJuT1ZTbG1wUGY4blFXTHk1VlFB+4Ay+kLEQyUBSiY+EUG6RCUBSiY+EUG6RSH7gTIy+kIkrEMlAU1qRSgehkQlAU1qRSgehkVjOTFhNmQ4OTUtNWJiZC00Yzk2LWI0ODQtMWVkYjk2M2ZlZWRj+4EyN/pCJLZDJQFKJjxgXoREJQFKJjxgXoRFV0hsSENVUlpIbW5HWV9odHdSeTJxZFM3WPuBMjP6QiSuQyUBSiY8Zg2IRCUBSiY8Zg2IRVUzNjk4MjUzNjI1MDM0Njc2OTQ2MDQ2+4A4+kLQQyUBSiY+MRS+RCUBSiY+MRS+RSH7gTEw+kLUQyUBSiY9GGySRCUBSiY9GGySRVI3NDUyNjY5MDM0MTc4MzI3Njk0+4EyMfpCJKpDJQFKJj4jaYZEJQFKJj4jaYZFIfuBMzT6QiQBhEMlAUomPlcfrkQlAUomPlcfrkVqUlgtZjYwNzkzYjEtMGVlZi00Y2E0LTgyYzUtZWU4YTNiNWNkYWI5LTAwNfuBNDj6QiQBoEMlAUomQQoxvkQlAUomQQoxvkUh+4E3MvpCJAKQQyUBTWpFKVOWRCUBTWpFKVOWRSH7gTQx+kIkAZJDJQFNTgN/RqhEJQFNTgN/RqhFZTY0NjUxMDE2NDMwMjQ0NTIyMTc0MDIzMDQ4MTg0NjIwMzQ4MDc0+/uGdmVyc2lvbsL7
|
||||
.owneriq.net TRUE / TRUE 1786504662 si Q7520753811633417448P
|
||||
.adx.opera.com TRUE / TRUE 1783480663 UID OPUb598e447ff4b444484a3e5b793c7de50
|
||||
.c.appier.net TRUE / TRUE 1799622470 _auid uRFPn0q_B3iJ-ONGdnZBZQ
|
||||
.clickagy.com TRUE / TRUE 1802646470 cb ZZxNii4CsNrNHhf4fvTcGhok
|
||||
.sportradarserving.com TRUE / TRUE 1799536067 zuuid 0c453c2e-5e55-4fe3-9049-740eec090ceb
|
||||
.sportradarserving.com TRUE / TRUE 1799536067 zuuid_k 1
|
||||
.sportradarserving.com TRUE / TRUE 1799536067 zuuid_lu 1768086466
|
||||
.sportradarserving.com TRUE / TRUE 1799536067 zuuid_k_lu 1768086466
|
||||
.mfadsrvr.com TRUE / TRUE 1799622466 tuuid 5e4703f4-14e0-453b-9026-9d49c268eb07
|
||||
.mfadsrvr.com TRUE / TRUE 1799622466 tuuid_lu 1768086466
|
||||
.mfadsrvr.com TRUE / TRUE 1799622470 ssh !minutemedia=1768086470!bidswitch=1768086467!rise=1768086466!smaato=1737765833!google=1737749553!yieldmo=1737749319!intentiq=1737749112!openweb=1737748827!triplelift=1737748799!onetag=1712791426!taboola=1712791378!sovrn=1708616102!mgid=1704742287
|
||||
.creative-serving.com TRUE / TRUE 1799190470 tuuid d76dec14-1b37-413d-9634-f86f69927815
|
||||
.creative-serving.com TRUE / TRUE 1799190470 tuuid_lu 1768086470
|
||||
.company-target.com TRUE / TRUE 1802300867 tuuid 50772b55-2539-48f4-9792-491248fd76f9
|
||||
.company-target.com TRUE / TRUE 1802300867 tuuid_lu 1768086466|eqx:0|ix:-186|rp:-349|tlx:-349
|
||||
.mgid.com TRUE / TRUE 1799622477 muidn o08rOa33HNvb
|
||||
.a-mx.com TRUE / TRUE 1799622477 amdt_t p::1704742288432
|
||||
.a-mx.com TRUE / TRUE 1799622477 amuid2 7a9a0eaa-8763-494f-a19c-ff6c08c88f76
|
||||
.a-mx.com TRUE / TRUE 1799622477 pamdt_t p::1704742288432
|
||||
.a-mx.com TRUE / TRUE 1799622477 pamuid2 7a9a0eaa-8763-494f-a19c-ff6c08c88f76
|
||||
.adhaven.com TRUE / TRUE 1786504662 uid 4c_c553ec4a-2731-4d1a-882a-843e046d4c06
|
||||
.media.net TRUE / TRUE 1799536071 data-o 276afcb7-5c3a-406c-8d05-8a2894744407~~3
|
||||
.media.net TRUE / TRUE 1799622475 data-pbs setstatuscode~~1
|
||||
.ctnsnet.com TRUE / TRUE 1799622469 cid 39a120f51a3e40d588e976fbafe13e6f
|
||||
.betweendigital.com TRUE / TRUE 1799622470 dc was1
|
||||
.betweendigital.com TRUE / TRUE 1799622470 tuuid b16f2b86-1f09-5309-b32b-76b7d6b7e147
|
||||
.betweendigital.com TRUE / TRUE 1799622470 ut aWLbxgAGJjjwjhvb2mDqv4a1-1UE-S_2NDFWRQ==
|
||||
.traversedlp.com TRUE / TRUE 1797620838 v1.cookieId s%3A3423a7ae-bcd9-4c3a-8e04-72bd2cbd9b0c.pqvYvjrrzijfWRft1Xi2w9q4NyfAW5Lgf3CLcgU1jjk
|
||||
.alocdn.com TRUE / TRUE 1783516591 uuid bc8a2178-c61f-4230-b4b4-9c1c65d13081
|
||||
.socdm.com TRUE / TRUE 1802646471 SOC ZZ9oQsCo5ugAADzpoEYAAAAA
|
||||
.sundaysky.com TRUE / TRUE 1802646478 sskyu d6.680b1a7f159a4c48921f356b642f47a9
|
||||
.sundaysky.com TRUE / TRUE 1802646478 sskyCreationTime 1704949195932
|
||||
.bfmio.com TRUE / TRUE 1799622466 __io_cid 248c815d-b156-4db9-8a92-46c25764dd54
|
||||
.bfmio.com TRUE / TRUE 1799622466 __103_cid 7b3a0d56-9687-4b59-b959-b7bc82b68d2a
|
||||
.bfmio.com TRUE / TRUE 1799622466 __106_cid 248c815d-b156-4db9-8a92-46c25764dd54
|
||||
.bfmio.com TRUE / TRUE 1799622466 __168_cid AADBck7KgtEAABjN509uAw
|
||||
.bfmio.com TRUE / TRUE 1799622466 __147_cid d6.680b1a7f159a4c48921f356b642f47a9
|
||||
.undertone.com TRUE / TRUE 1799643429 UID_EXT_46 248c815d-b156-4db9-8a92-46c25764dd54
|
||||
.rtb.mx TRUE / TRUE 1799622477 amdt_t p::1708616096070
|
||||
.rtb.mx TRUE / TRUE 1799622477 amuid2 7a9a0eaa-8763-494f-a19c-ff6c08c88f76
|
||||
.rtb.mx TRUE / TRUE 1799622477 pamdt_t p::1708616096070
|
||||
.rtb.mx TRUE / TRUE 1799622477 pamuid2 7a9a0eaa-8763-494f-a19c-ff6c08c88f76
|
||||
.onaudience.com TRUE / TRUE 1799622469 cookie 64096b5cf64dd62a
|
||||
.ml314.com TRUE / TRUE 1783480600 pi 3642252982602432536
|
||||
.go.affec.tv TRUE / TRUE 1799622470 ck 65d769bed154af0001cede82
|
||||
.go.affec.tv TRUE / TRUE 1775862470 pt eyJhbiI6eyJkdCI6MTc2ODA4NjQ3MCwiaWQiOiIxNDQ2NjY0NjMzMDYyNDU1NzM4IiwibHMiOjE3NjgwODY0NzB9LCJ0dCI6eyJkdCI6MTc2ODA4NjQ3MCwiaWQiOiJKbGplYm1lVDhTWFpQWlFWVHFQdUJ3PT0iLCJscyI6MTc2ODA4NjQ3MH0sInRkIjp7ImR0IjoxNzY4MDg2NDcwLCJpZCI6IjI0OGM4MTVkLWIxNTYtNGRiOS04YTkyLTQ2YzI1NzY0ZGQ1NCIsImxzIjoxNzY4MDg2NDcwfSwidiI6MH0=|1768086470|6b354ac39182a0f3e7e3fa9f9ed0005b01ab7646
|
||||
.c.bing.com TRUE / TRUE 1786249799 SRM_B 10188FE1CFA1634236249C51CE0F62C0
|
||||
.clarity.ms TRUE / TRUE 1786249800 MUID 10188FE1CFA1634236249C51CE0F62C0
|
||||
.alcmpn.com TRUE / TRUE 1799622493 _3ci 4898dc00-f791-11ee-87da-35dab27f2b66
|
||||
.onetag-sys.com TRUE / TRUE 1802273212 OTP HTJCyV8vRH5apyIbS4jgTGmh02TGaXE7yVXssIgnxhE
|
||||
.riverside.fm TRUE / FALSE 1787692546 ajs_anonymous_id 21dd7898-1bfc-402f-b77a-7b431fcb8478
|
||||
.riverside.fm TRUE / FALSE 1787243493 cookiehub eyJhbnN3ZXJlZCI6ZmFsc2UsInJldmlzaW9uIjoxLCJkbnQiOmZhbHNlLCJhbGxvd1NhbGUiOnRydWUsImltcGxpY3QiOnRydWUsInJlZ2lvbiI6IkcwIiwidG9rZW4iOiJwanhpdlJGdGpCeWw5bE1UTUxpWHNac3hWTzREdnNXb2c0eWRlYUhZNENlcmgxcmdhWkhaWVFGa3BWN0JTd1JJIiwidGltZXN0YW1wIjoiMjAyNC0wNC0xNlQxNzo1OTo1NC4wNTdaIiwiYWxsQWxsb3dlZCI6dHJ1ZSwiY2F0ZWdvcmllcyI6W10sInZlbmRvcnMiOltdLCJzZXJ2aWNlcyI6W119
|
||||
.riverside.fm TRUE / TRUE 1787243493 _zitok e8af6ff1d02a6d1909bc1713290389
|
||||
.riverside.fm TRUE / TRUE 1784140212 __stripe_mid 84ab569e-8d4f-4816-a632-04e6d62c32405c3e59
|
||||
.riverside.fm TRUE / FALSE 1790267493 _ga GA1.1.1848369474.1713290394
|
||||
.riverside.fm TRUE / FALSE 1789403493 _uetvid 21509ba0fc1b11ee99478f310d5b7258
|
||||
.riverside.fm TRUE / FALSE 1790716547 _ga_PF9PK8DC9Z GS2.1.s1756156546$o8$g0$t1756156546$j60$l0$h1160639619
|
||||
.d.adroll.com TRUE / TRUE 1786072565 __adroll 6cc6d395376a1bb9f56de1a8c78c955f-a_1713364488
|
||||
.d.adroll.com TRUE / TRUE 1786072565 receive-cookie-deprecation 1
|
||||
.adroll.com TRUE / TRUE 1786072565 __adroll_shared 6cc6d395376a1bb9f56de1a8c78c955f-a_1713364488
|
||||
.adroll.com TRUE / TRUE 1786072565 receive-cookie-deprecation 1
|
||||
.demdex.net TRUE / TRUE 1783638478 demdex 64651016430244522174023048184620348074
|
||||
.demdex.net TRUE / TRUE 1781725180 dextp 21-1-1766173172009|477-1-1766173172826|481-1-1766173173827|843-1-1766173174827|771-1-1766173175829|1957-1-1766173176827|12105-1-1766173177830|575-1-1766173178828|53196-1-1766173179826|121998-1-1766173180825
|
||||
.dpm.demdex.net TRUE / TRUE 1783638478 dpm 64651016430244522174023048184620348074
|
||||
.go.sonobi.com TRUE / TRUE 1799622514 __uis fee5909e-22fd-42a0-a1fb-e28d64e05182
|
||||
.synthesis.com TRUE / FALSE 1775770716 _ga GA1.1.2026762825.1731628556
|
||||
.synthesis.com TRUE / FALSE 1775770733 _ga_KQHY76450D GS1.1.1741210716.45.1.1741210732.44.0.0
|
||||
.synthesis.com TRUE / FALSE 1775770733 _ga_MJL598MDNX GS1.1.1741210716.45.1.1741210732.44.0.0
|
||||
.a-mo.net TRUE / TRUE 1799622514 amuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.a-mo.net TRUE / TRUE 1799622514 pamuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.prebid.a-mo.net TRUE / TRUE 1799622514 sd_amuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.prebid.a-mo.net TRUE / TRUE 1799622514 __amc 2888_1712791451_1768086514
|
||||
.prebid.a-mo.net TRUE / TRUE 1799622514 psd_amuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.crwdcntrl.net TRUE / TRUE 1791414601 _cc_id 3cf9e41188988b992aee1510314411e1
|
||||
.crwdcntrl.net TRUE / TRUE 1791414601 _cc_dc 0
|
||||
.crwdcntrl.net TRUE / TRUE 1791414479 _cc_cc "ACZ4nGNQME5Os0w1MTS0sLC0sEiytDRKTE01NDU0MDY0AYqmGjIAQWbS7XNLHi%2F7wc8AAwJTJr1QZWwrZ%2FjPyMgwEYndhcReMvsAExOE%2FYERLHJh8RwWVJFzRw8xo4rM7tZCFbi39ik3qshhDGMa%2FmuiCsz8cMEcVeTsvR5VVJFLpx6xoYps%2BlOIKvD2oyWqwO%2BNU9CsBgAgHmmA"
|
||||
.crwdcntrl.net TRUE / TRUE 1791414479 _cc_aud "ABR4nGNgYGDITLp9jgEGmBgYuGaAGFxNn4EkAE3%2BBJg%3D"
|
||||
.outbrain.com TRUE / TRUE 1775862477 obuid 83bc6354-0805-4310-befc-80a97066c1a2
|
||||
.inmobi.com TRUE / TRUE 1799622477 iid ID5-5-1342167a-ef28-4e21-bab5-fd43f14a737a
|
||||
.inmobi.com TRUE / TRUE 1799622469 gob_cookie YES
|
||||
.inmobi.com TRUE / TRUE 1775862469 idsp_c d8fbeb2e-e64d-4ded-8362-c043cf92d3c3
|
||||
.creativecdn.com TRUE / TRUE 1797620685 g 88s83VQB5MgVwZvDd6Z8_1737748773872
|
||||
.creativecdn.com TRUE / TRUE 1797620685 c 88s83VQB5MgVwZvDd6Z8_rvpPdB9Ykz6pEuCHxRxe_1766084684882
|
||||
.creativecdn.com TRUE / TRUE 1797620685 ts 1766084684
|
||||
.sync.a-mo.net TRUE / TRUE 1799622478 sd_amuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.sync.a-mo.net TRUE / TRUE 1799622478 psd_amuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.smartadserver.com TRUE / TRUE 1800299087 TestIfCookieP ok
|
||||
.mediawallahscript.com TRUE / TRUE 1800644838 mCookie cc96bf10-da8d-11ef-9bbb-13760a7a1a50
|
||||
.mediawallahscript.com TRUE / TRUE 1800644838 mUserCookie %7B%226d7065a93a3c4b7fac2bbe5cf7d31996%22%3A%5B%22a7bfe61c1f5205b22e34465d03fefacb%22%2C%227d5b04e46ff8eaf91bec603bdbc20bba1fa3b4fa%22%2C%22139c2033b0bb853ae6140cbd2ca1f01d680097a946f9a07139d46987737158b8%22%5D%7D
|
||||
.udmserve.net TRUE / TRUE 1797620686 dt 778C4ACD-EEFB-3BB1-8558-9CE42AFF4D9C
|
||||
.udmserve.net TRUE / TRUE 1797620686 udmts 1766084685.0
|
||||
.ad-stir.com TRUE / TRUE 1797620787 uid 92c9d51d-b1f9-4ed5-aed2-5a64d6d9fcb9
|
||||
.a.usbrowserspeed.com TRUE / TRUE 1797620804 tuid e9c2099e-35ab-4932-afa1-aa1367b10f1e
|
||||
.insightexpressai.com TRUE / TRUE 1783480594 DW 00000000-0000-000b-a862-6a1737752050
|
||||
.agkn.com TRUE / TRUE 1799622482 ab 0001%3AE8XKtnaP2Z0ZuSwwKJa%2Fca70CcxR1DZIhCajAiTWekfdmnpivPSPKlV1KU2AScJ9zOSVGGcwbF8s%2FIv51kx8ouEYbisZ%2Bu18RoxCUZYFIqgUvyb6tl9OYN0MbljWX0KC88Xyo%2FN1vB5ndGqjMM95YT%2BDEtG4PxU05hCPTIgfyYxqL7oxpOdAk958wz%2BoN1VWt9qTn81D90opZR%2BdWINFNGAgmGMwaFdtbK%2FTiHgYdXrfSL%2B6UHcDR8bWcMNKyF9KdMJ4uFrtDZXCB3PwyO8u7wByYLoxIbyWxn4fIiiID3LBIL%2FtQyBHrd%2FOio2TxWzDruQ6o1NVPSJY7WzuoJ0oFQ%3D%3D
|
||||
.agkn.com TRUE / TRUE 1797709222 u C|0EAAAAAAAMNhmpQAA4ABYAQAHAAAAAAIAEU___x4AAAAAAGOFrgAAAAAZJD-mAAAAAAd2kfAAAAAAJKG5lQA
|
||||
.medialiance.com TRUE / TRUE 1800644702 mCookie 89440e60-dab1-11ef-8ec3-892a738b03da
|
||||
.medialiance.com TRUE / TRUE 1800644702 mUserCookie %7B%22e5cd834d8052bae2c694ddeaeca6f999%22%3A%5B%22b734715e576a5b620291c43f3b5a280f%22%2C%22d97ab4c28d7a42897d04af42610829b0567be6ea%22%2C%221b042a61a1412bc36bc3d3631335628355f71e35c3a1ab246d663baa06c947d3%22%5D%7D
|
||||
.contextweb.com TRUE / TRUE 1799190477 V Pv9rW4ongCVL
|
||||
.contextweb.com TRUE / TRUE 1799622471 pb_rtb_ev 3-1w32|8kt.0.1|7Eb.1.1|8ly.l.1|8px.5|8tI.5|7Nq.5|7Bj.4.CAESEObJmDpmPVBEKUyOQ9zVbuY|8sZ.5.78e498bf-f874-4fc4-90db-ec299869f88b|8dw.5.1|8iH.5|8hH.5|7TY.0|7TZ.0.1|7fJ.5|8fr.5|88e.5|7bq.2bW.1|7br.11C.1|8nM.8.1|7bs.9.1|8fP.5|6zB.1.7b3a0d56-9687-4b59-b959-b7bc82b68d2a|8gU.2bW.1a14e546-92a3-4ee7-a6ad-dc4e8f83d083|80p.2bW.1|8dQ.1.1|7dW.0.1|87G.5|8bO.5|2N.1.AQALN3bf5gd9IQFydVqNAQA8IwEBAQEBAQEBAQEBAQEBAQEB|7GB.8.1|7RY.5|8vg.5.1|8ue.5.78e498bf-f874-4fc4-90db-ec299869f88b|7dN.2bW.AADBck7KgtEAABjN509uAw|4is.1.CAESENz6rsahLafnUk4itvuDrpI|7Xz.5|8rx.1.LNYXWIAC-1G-2KTD|7I7.5|3oy.5.bad985e7-8794-4157-b22d-37333612913c-654168d8-5553|82A.5|8ro.5|8f1.0.A4879159953770555400|86L.5|8i8.2bW.1
|
||||
.contextweb.com TRUE / TRUE 1799190477 VP part_Pv9rW4ongCVL
|
||||
.contextweb.com TRUE / TRUE 1799622471 pb_rtb_ev_part 3-1w32|8kt.0.1|7Eb.1.1|8ly.l.1|8px.5|8tI.5|7Nq.5|7Bj.4.CAESEObJmDpmPVBEKUyOQ9zVbuY|8sZ.5.78e498bf-f874-4fc4-90db-ec299869f88b|8dw.5.1|8iH.5|8hH.5|7TY.0|7TZ.0.1|7fJ.5|8fr.5|88e.5|7bq.2bW.1|7br.11C.1|8nM.8.1|7bs.9.1|8fP.5|6zB.1.7b3a0d56-9687-4b59-b959-b7bc82b68d2a|8gU.2bW.1a14e546-92a3-4ee7-a6ad-dc4e8f83d083|80p.2bW.1|8dQ.1.1|7dW.0.1|87G.5|8bO.5|2N.1.AQALN3bf5gd9IQFydVqNAQA8IwEBAQEBAQEBAQEBAQEBAQEB|7GB.8.1|7RY.5|8vg.5.1|8ue.5.78e498bf-f874-4fc4-90db-ec299869f88b|7dN.2bW.AADBck7KgtEAABjN509uAw|4is.1.CAESENz6rsahLafnUk4itvuDrpI|7Xz.5|8rx.1.LNYXWIAC-1G-2KTD|7I7.5|3oy.5.bad985e7-8794-4157-b22d-37333612913c-654168d8-5553|82A.5|8ro.5|8f1.0.A4879159953770555400|86L.5|8i8.2bW.1
|
||||
.trkn.us TRUE / TRUE 1783004736 barometric[cuid] cuid_67946932-4589-41ab-98a0-895e3e2d97a8
|
||||
.rubiconproject.com TRUE / TRUE 1799622478 khaos M6CF4TG8-W-J70S
|
||||
.rubiconproject.com TRUE / TRUE 1799622478 audit 1|tcR/wBEzWcKBeiMwxwaIMJH/wrGgPvJ3EHTCxBIN+XkJG9/P5Pbd26X+G7tBI/pLK4KewJT0BBosa0K79A6XVh3ukALJD0TTOcV4pE4CozChJWL1SayQt/FdJMTEemORX1vKT1ONdRY=
|
||||
.rubiconproject.com TRUE / TRUE 1799622478 khaos_p M6CF4TG8-W-J70S
|
||||
.rubiconproject.com TRUE / TRUE 1799622478 audit_p 1|tcR/wBEzWcKBeiMwxwaIMJH/wrGgPvJ3EHTCxBIN+XkJG9/P5Pbd26X+G7tBI/pLK4KewJT0BBosa0K79A6XVh3ukALJD0TTOcV4pE4CozChJWL1SayQt/FdJMTEemORX1vKT1ONdRY=
|
||||
.rubiconproject.com TRUE / TRUE 1775862478 receive-cookie-deprecation 1
|
||||
.turn.com TRUE / TRUE 1783638477 uid 7289271102826593249
|
||||
.yieldmo.com TRUE / TRUE 1799622476 yieldmo_id 3eHPvHHbmPHxStMoIXOR%7C1737849600000%7C3724524149782542238%7C3488079986244395387
|
||||
.bcbst.com TRUE / FALSE 1776969422 WT_FPC id=23ab50c55541c3198981742409300028:lv=1742409421989:ss=1742409300028
|
||||
.unchained.com TRUE / TRUE 1789657964 osano_consentmanager_uuid 59c5c276-5ecc-493b-8730-858eaf3c0a5f
|
||||
.unchained.com TRUE / TRUE 1789657964 osano_consentmanager rPSs2F3XcQDGXcdQCAI3PxJj_1u57qW_iTlDLyjgVTeNX-uK8InVJC0TTXTwBZ_fQDe5D8H7eSSH-WBNLcwyGO7r7-VKutZLjTTahHSxQgotJZgsxPatac9bLWOQyeah774yEWXH_7wYU2HwtHpLepF3TEH89eLciFtN8TN-s0TOfe4RS0eOoU1eSBl7t3UcmOML_Utx-arUek685WuQRGnaFcEIk_Z8J8-dYEKGyw4Mpp8XqCODSWuEgZVikxUIg5hmrBYZviEdapwxILbVlQ2dL-IiUZM9Say0a6o2Q_1xIxvg-qif3EnY_jBsv7wa6-PGLRQTwwo=
|
||||
.unchained.com TRUE / FALSE 1792680928 ab.storage.deviceId.5ed20afa-515f-4b9a-a9f1-5cf8769574ef g%3Af2f6ef8d-1172-1d40-a491-ae8efac5929e%7Ce%3Aundefined%7Cc%3A1758117898590%7Cl%3A1758120460258
|
||||
.unchained.com TRUE / FALSE 1792680928 ab.storage.userId.5ed20afa-515f-4b9a-a9f1-5cf8769574ef g%3Aeddf5362-4840-44fa-9ea6-cca1c2bfc860%7Ce%3Aundefined%7Cc%3A1758117898588%7Cl%3A1758120460258
|
||||
.unchained.com TRUE / FALSE 1792680928 ab.storage.sessionId.5ed20afa-515f-4b9a-a9f1-5cf8769574ef g%3Ab553b88d-0448-ca46-18e3-355394901910%7Ce%3A1758122728118%7Cc%3A1758120460258%7Cl%3A1758120928118
|
||||
.my.unchained.com TRUE / TRUE 1789657965 __stripe_mid 7e35a7e6-2671-4130-8964-ccd5ac2894477168e1
|
||||
ten31.vc FALSE / FALSE 1777385004 ss_cvr 15a4855b-9c66-4647-a7f8-61aa8b6595be|1730144511490|1731602788023|1742825003097|3
|
||||
.www.linkedin.com TRUE / TRUE 1790346598 bscookie "v=1&202503241857592b5ead33-6f67-4547-8ead-51dcfe02910aAQH8ycCs5-tSCgNIGNLairKP-yifEUhF"
|
||||
.www.linkedin.com TRUE / TRUE 1784050017 li_rm AQG7XdvCSOs9BAAAAZd64ZXVLmo_dWkMhTknsO1hJmw1642__4KUBhOQk-IPq4F333CgLCTedSmyIWVHvkQrz_B0m3jw4uth0WO67p5suv8V2zWX4QuOvwaxukP7Q8EiAFb6y7uUwulv84mX-3OXQiIsENB_-OsLPgk1FgQDVkIDd_LGlSFaPANKLOAK2SKTCaBzkWddFr2ESOryCmjzEtioqeeV9L-rC07LBeuIDhFtB-maFTKp0pxdxqJoHSAo_wiDIZnO3NNTyWU4Qe7tSN6HvaOQ-D7Xepm2MZYdIpRAlkvYkMnKbNSBYyV4CylY0hkzpNvLQgkFnoQsvJUQ9Q
|
||||
.www.linkedin.com TRUE / TRUE 1790346598 JSESSIONID "ajax:4171029513032656218"
|
||||
.www.linkedin.com TRUE / TRUE 1784062922 li_ep_auth_context AHVhcHA9c2FsZXNOYXZpZ2F0b3IsYWlkPTI5NTM3MjkzMixpaWQ9Mzg1Mjk1NDQ0LHBpZD00OTE4NTMzNTMsZXhwPTE3NTUxMTg5MjE0NTIsY3VyPXRydWUsc2lkPTE1Mzc4NTAxMTYsY2lkPTIwMTMyMzk2ODMBresxvFmgTpwVa7MvInSzFcXh5Gk
|
||||
.www.linkedin.com TRUE / TRUE 1790346598 li_at AQEFAHQBAAAAABb-2ykAAAGYCfm4NwAAAZmlVHycTgAAF3VybjpsaTptZW1iZXI6MzI2MTc2NzUyNv3G6zHnnd48jDJY2beVMl5kbCvn2KO6Gdn6NeRn_G1-hCe3g8eT0xMvjx3ANoSIRzueX9tT1VWF6P0UL28EArA3bRzI3uRWKO0tc5JNeNSywAlkv12xcNnKL8C7yGiEw1E01ROKaeK7oSPUkaUVI62vV-0aI0QG2SYtvnIkbiSkn9VGbLBIJnnvxbwrG4S_7A99DQ
|
||||
.inflightinternet.com TRUE / FALSE 0 rxVisitor 1743863097950UC0EEQA5P7KC2DRQ7BM3GGT4OU23FTM9
|
||||
.inflightinternet.com TRUE / FALSE 0 FLIGHT_TRACKER_STORED {%22departureAirportCode%22:%22BNA%22%2C%22destinationAirportCode%22:%22ORD%22%2C%22flightNumber%22:%22SKW6259%22%2C%22departureTime%22:%222026-03-31T16:11:00.00Z%22%2C%22arrivalTime%22:%222026-03-31T17:27:00.00Z%22}
|
||||
.inflightinternet.com TRUE / FALSE 0 LOGGER_DATA {%22airlineCode%22:%22AAL%22%2C%22flightNumber%22:%22SKW6259%22%2C%22mac%22:%227A:6D:B0:B5:E8:ED%22}
|
||||
.inflightinternet.com TRUE / FALSE 0 DYNATRACE_THEME default
|
||||
.inflightinternet.com TRUE / FALSE 0 flightIdentifier {%22tailNumber%22:%22N759EV%22%2C%22departureAirportCode%22:%22KBNA%22%2C%22destinationAirportCode%22:%22KORD%22}
|
||||
.inflightinternet.com TRUE / FALSE 0 hasActiveInflightSession true
|
||||
.inflightinternet.com TRUE / FALSE 0 airlineCode aal
|
||||
.inflightinternet.com TRUE / FALSE 0 dtCookie v_4_srv_21_sn_MME8PSIQ380J5EFVLH66ARG76FJG56J9_perc_100000_ol_0_mul_1_app-3Aa102791a62dd9f00_1_app-3A4eca8c42196ba4a2_1_app-3Aea7c4b59f27d43eb_1_rcs-3Acss_0
|
||||
.inflightinternet.com TRUE / FALSE 0 env prodp
|
||||
.inflightinternet.com TRUE / FALSE 0 loggerData {%22airlineCode%22:%22AAL%22%2C%22flightNumber%22:%22SKW6259%22%2C%22mac%22:%227A:6D:B0:B5:E8:ED%22}
|
||||
.inflightinternet.com TRUE / FALSE 0 rxvt 1774976057213|1774974154984
|
||||
.inflightinternet.com TRUE / FALSE 0 dtSa false%7CC%7C4%7CWI-FI%20PACKAGES%7Cx%7C1774974257207%7C174240510_433%7Chttps%3A%2F%2Fwifi.inflightinternet.com%2Fapp%2Faal%2Fifc%2F%7C%7C%7Cgobrowse%7C
|
||||
.inflightinternet.com TRUE / FALSE 0 dtPC 21$174206057_810h1p21$174268351_454h1vMFQEHSHFARVKFMKVPWJURICDEAJLMUQW-0e0
|
||||
.airbornesecure.inflightinternet.com TRUE / TRUE 1805384898 __stripe_mid 414200e8-7823-41f0-afc8-3f42d2ef439691897d
|
||||
.paypal.com TRUE / TRUE 1796165169 enforce_policy ccpa
|
||||
.paypal.com TRUE / TRUE 1779902570 cookie_check yes
|
||||
.paypal.com TRUE / TRUE 1779902570 d_id 80fb76c2e17a49e1a765a042b42e17241745342570275
|
||||
.paypal.com TRUE / FALSE 1796165168 TLTDID 27040534859840361107447354011634
|
||||
.paypal.com TRUE / TRUE 1796165182 ts_c vr%3D0658813d1960a5515860f94cfc3d321b%26vt%3Ddc142d6019a0a55100281bbcfb685727
|
||||
.paypal.com TRUE / TRUE 1796164903 _iidt CH4Hh6drZWFH8o+y2QON+f528H0a7DM3JGqCL5uu1wpJsHz46R4JUJJOav8LNV5X3jmFJjsXrVbEApq3l5Q8MuB8Cux+nm2vd8NclJ0=
|
||||
.paypal.com TRUE / TRUE 1799188912 login_email grant.gilliam%40gmail.com
|
||||
.paypal.com TRUE / TRUE 1799188927 rmuc 9lroqoP1vjt1EudVvIA_HPq_C19q2vzSEp2JWJOfcaqyHnYBt5tu-KrW3yZ1Sy158fuVuI-DZkOS8iS0YI3FQPx-8aqHquZdiOgK0P7QA04z2BfeyxgIAknf0QAAut48NYUq7b2fx26EFIwu2to7DqKzmyw-bVv1zQCz90PXRAzB5iKcEhqY_R3y34GqPCZHXNJE7WX6n9zbwOB3Q2NLy1nqH8G
|
||||
.paypal.com TRUE / TRUE 1796164928 cookie_prefs T%3D0%2CP%3D1%2CF%3D1%2Ctype%3Dimplicit
|
||||
.paypal.com TRUE / TRUE 1799189167 ui_experience tokenType%3Dsoftware_token_authenticator%26tokenIdentifier%3DWIquIrjeoFYEfLoCrFjE_dUugfLYs0LhEVfAIg2-XuT4cB6jNZ0ONljYUtZx1kzBMjPbPavKH5ReKg5E
|
||||
.paypal.com TRUE / TRUE 1796165182 ts vreXpYrS%3D1796165181%26vteXpYrS%3D1764630981%26vr%3D0658813d1960a5515860f94cfc3d321b%26vt%3Ddc142d6019a0a55100281bbcfb685727%26vtyp%3Dreturn
|
||||
.paypal.com TRUE / TRUE 1799189168 KHcl0EuY7AKSMgfvHl7J5E7hPtK FIfTcfpEkB2i1XvmAN4PP4SeJq5aSSd9DNTO8-_lo5rhvENJIgcciW9fAf8jzsCnPpD2zH2SA-BfXQMh
|
||||
.paypal.com TRUE / TRUE 1799189168 sc_f gkBt9_7bEOc05CHYIB-CZVSf6hnGCUjMm4o0U1EEZQ5TVg9WJlcdAf0KGbXipy31piIid40JIe5XcYCDZCVIhl4V1qs4AYsE6yb0iG
|
||||
.paypal.com TRUE / TRUE 1799189168 ddi cQ1FNbgqR-YWLJ15JSTC4edfi7MpfuC5MlVWS4HsWm-ssPIuApHPwVILKObl3lofRerCE1-FEkv9d-OVEHyhVBQqH8cgn3xbgcJnpUkZ1O4wMYh8
|
||||
.chase.com TRUE / FALSE 1807901097 v1st 951B54D03A5ADC53
|
||||
.chase.com TRUE / TRUE 1776350059 chase_campaign_data SourceCode=OS0001&iq_id=
|
||||
.chase.com TRUE / FALSE 1807901097 s_vi [CS]v1|951B54D03A5ADC53-423DCF575550D14A[CE]
|
||||
.chase.com TRUE / TRUE 1807901097 adtoken.chase.com |DYN|S85Tt1LnADdBsXuTfTrS7%2Fbn8yqG9rDCjlio3e%2BMLkhqtNC7mBTfZZt09%2B7uuG%2BaeeedqbPa95IcTyVOkgx5i1DXGkdn9R3kBzVcvy4ErOjUvXQpxD5Cpgcfo8DuGJMc%7CZoQo7mE96ssrsP2JUB%2FjifrYecMgP2Pa%2B7tpIzl%2B6MT2vvJgkyFQgGf%2ByEIopgCi
|
||||
.chase.com TRUE / FALSE 1807901097 NyJB5Jgn A-IWXeOcAQAAzSp6FikrPh4IyzXygB0y02ND6fi5NRhDkX-8S8Zv9KkNwt9hAWvCVQyucmVTwH9eCOfvosJeCA|1|NO_BIT|c039b4f5bec6e784a132343dce8fcfe170fa321d
|
||||
.chase.com TRUE / TRUE 1804880699 BRAND_1_0 WEALTH
|
||||
.chase.com TRUE / TRUE 1804877098 PC_1_0 pfid%3D10383181%7Csegment%3DPAF%7Csegg%3DPAF%7Czip%3D37027-1532%7CECI%3D0346242280%7CAOC%3D6615%2C6653%2C%7Cpm%3DATM%2CCHK%2CCHK%2CSAV%2CBAC%2CBAC%2CALA%2CALS%7CRPC%3D0550%2C0404%2C%7Capc%3D100%2C067%2C080%2C064%2C010%2C%7Clocale%3Den_us%7ClastUpdate%3D2025-04-21%7ClastSent%3D2025-04-21%7Cpod%3D07EA%7Cusrtp%3DPR%7Cpftp%3DPER%7Csc%3DTN%7C
|
||||
.chase.com TRUE / FALSE 1807901099 AMCV_EA673DFC5A2F19060A495C9C@AdobeOrg 1914845758|MCIDTS|17564|MCMID|78587949278339082538316563911219460485|MCAID|NONE|MCOPTOUT|isoptedout-false|MCAAMLH||MCAAMB||MCCIDH|1019576346|MCSYNCSOP|411-17568|vVersion|2.3.0|TESTPROFILE|false|IsCustom|true
|
||||
.chase.com TRUE / TRUE 1804880699 _iscpo 07EA
|
||||
.chase.com TRUE / TRUE 1804880699 DEFAULT_PAGE_1_0 octagonOverviewDashboard
|
||||
.twitter.com TRUE / TRUE 1782324962 personalization_id "v1_BPqyvG9JD5AM/EiiDpIOTA=="
|
||||
.twitter.com TRUE / TRUE 1787107244 guest_id_marketing v1%3A175254724421271077
|
||||
.twitter.com TRUE / TRUE 1787107244 guest_id_ads v1%3A175254724421271077
|
||||
.twitter.com TRUE / TRUE 1787107244 guest_id v1%3A175254724421271077
|
||||
.t.co TRUE / TRUE 1782324962 muc_ads f0a4d615-2d82-4018-be9d-fa847c1b1cc5
|
||||
.goduke.com TRUE / TRUE 1780040693 visid_incap_3109055 12O3hjvaTjau1Wo/L9c77mHTOGgAAAAAQUIPAAAAAADgd0MG9tKPy5WEPkv2jsF9
|
||||
api.phantombuster.com FALSE / TRUE 1784673334 session vMmRJdC83mC7jcKh60wDuoeCT6EE1Q1JrHbQAZadXNE
|
||||
api.phantombuster.com FALSE / TRUE 1787859447 amplitude_device_id 1750113334053923537236069351
|
||||
.disqus.com TRUE / TRUE 1783888531 disqus_unique 1rp6lv2627db3
|
||||
.disqus.com TRUE / TRUE 1799622478 zeta-ssp-user-id 1rp6lv2627db3
|
||||
.chromewebstore.google.com TRUE / FALSE 1805841466 _ga GA1.1.1914643352.1750113338
|
||||
.chromewebstore.google.com TRUE / FALSE 1808253614 _ga_KHZNC1Q6K0 GS2.1.s1773693584$o7$g1$t1773693614$j30$l0$h0
|
||||
phantombuster.com FALSE / TRUE 1781650031 CookieConsent {stamp:%27HhuJjYqXCqaOyewhVggQ6Y15nrzwtSUvdW4WnuTUu8garuTH22muNg==%27%2Cnecessary:true%2Cpreferences:false%2Cstatistics:false%2Cmarketing:false%2Cmethod:%27explicit%27%2Cver:1%2Cutc:1750114031149%2Cregion:%27us-47%27}
|
||||
.linkedin-ei.com TRUE / TRUE 1782431038 bcookie "v=2&b2cebf06-4e82-405b-84a3-620f0d797b85"
|
||||
.nextlayer.capital TRUE / TRUE 1782160419 _reb2buid 752ba5c6-07cd-49b1-ac28-7508358b0f25-1751056419084
|
||||
www.ten31.xyz FALSE / FALSE 1785617475 ss_cvr 9e202335-e808-4d6e-9559-dcf4bdb0f6db|1751057469803|1751057469803|1751057469803|1
|
||||
.calendly.com TRUE / TRUE 1783859117 __stripe_mid a5c306c1-a69f-408c-8771-60c5fa5917dd4a27ad
|
||||
.calendly.com TRUE / TRUE 1783859083 OptanonAlertBoxClosed 2025-07-12T12:24:43.800Z
|
||||
.calendly.com TRUE / TRUE 1783859083 OptanonConsent isGpcEnabled=0&datestamp=Sat+Jul+12+2025+07%3A24%3A43+GMT-0500+(Central+Daylight+Time)&version=202501.1.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=83e3e526-39d4-462d-a3b9-f7fc0cdd26a0&interactionCount=2&isAnonUser=1&landingPath=NotLandingPage&groups=C0001%3A1%2CC0003%3A1%2CC0002%3A1%2CC0004%3A1&AwaitingReconsent=false&intType=1
|
||||
.calendly.com TRUE / FALSE 1783859115 ajs_anonymous_id f1bc62b0-b6b1-4650-9dec-737555e0c0a6
|
||||
.calendly.com TRUE / FALSE 1783859115 analytics_session_id 1752323115018
|
||||
.calendly.com TRUE / FALSE 1783859115 analytics_session_id.last_access 1752323115018
|
||||
.primal.net TRUE / TRUE 1802375175 __stripe_mid 992a6e6e-7e2d-4fc6-808c-34d093472745a9847d
|
||||
.squarespace.com TRUE / FALSE 1785164736 SS_MID 3055171d-2109-4415-8dc8-67e67ccc9f60
|
||||
.squarespace.com TRUE / TRUE 1785974242 IR_PI 20d8783e-56d7-11f0-8c1b-63794422bed6%7C1751414241665
|
||||
.squarespace.com TRUE / TRUE 1785248955 SS_ANALYTICS_ID a1a96488-e25b-4653-bd8b-e01cea208d5f
|
||||
.squarespace.com TRUE / FALSE 1785600940 _scid CACU7iWxruAeEvOr9q2G_PUVUG36W21R
|
||||
.squarespace.com TRUE / FALSE 1785600941 _sctr 1%7C1751346000000
|
||||
.squarespace.com TRUE / FALSE 1786028737 _ga GA1.1.277295834.1751414244
|
||||
.squarespace.com TRUE / FALSE 1785164737 _tt_enable_cookie 1
|
||||
.squarespace.com TRUE / FALSE 1785164737 _ttp 01JZ46S0AQBRTJZZSZ5J8XDKKJ_.tt.1
|
||||
.squarespace.com TRUE / FALSE 1785655435 _scid_r E4CU7iWxruAeEvOr9q2G_PUVUG36W21RsZWTPQ
|
||||
.squarespace.com TRUE / FALSE 1785164737 _uetvid 21f1067056d711f084c3b9ce4219e763
|
||||
.squarespace.com TRUE / FALSE 1785164737 ttcsid_C2ENC2QQV140ORDIO960 1751468737412::x48b425HPqqgdt634mr6.2.1751468737413
|
||||
.squarespace.com TRUE / FALSE 1785164737 ttcsid 1751468737412::I-XIdf8s62VM_nUhb1Kc.2.1751468737413
|
||||
.squarespace.com TRUE / FALSE 1786917443 _ga_1L8CXRNJCG GS2.1.s1752357442$o3$g0$t1752357442$j60$l0$h0
|
||||
.syuh.net TRUE / TRUE 1786028735 brwsr 20d8783e-56d7-11f0-8c1b-63794422bed6
|
||||
.support.squarespace.com TRUE / FALSE 1783004737 _pin_unauth dWlkPVptSTNNak5tWkRrdE1tUXpNQzAwWmpRMExUbGpOV1l0Tm1Zd1lXTTJOVGhqTW1ObQ
|
||||
.adnxs.com TRUE / TRUE 1775862514 uuid2 1446664633062455738
|
||||
.adnxs.com TRUE / TRUE 1775862477 anj dTM7k!M40<E:X*YF']wIg2C'$n4d`8!rdB[<ZuYAZgU6__Ny_!/'atsWVY`OVR$?hD?QBUrX@Nlqb_#VF.a3apf[[[Uk`4rHogB+W1vceWNTqbI0F*=?k!)X@g@@m?J]s3ky-i?fs`<MAh[?P+4h`k!C%Jr(g4AbKvTjjre++lQ./RyStDj$!rd^!tP7@(oqS$[pzxKrb=fHKZ1M1UoD+NNeB?]Tb>:t9upA#3Rt'X^Fru/+Xdh$X>//ECId2BWai$i]<!bOVf.pDfAPdQuVmhwwZ3d=1EibY:mP0@@@m6d7TI_bLOWU<!?8WtH9#pPT>m[A$UBcKbCxr^=6d[wc9RkhB2?Pkz/X#8!VFwEWPvED^aC?429-W18Pqx$sRr6QPL@dv9<Ly$$1F23<ExW>salD[=0K$O^$+=cHe`9zz0BHZE:Z:EZF0Id%*g0D(36I3l
|
||||
.adnxs.com TRUE / TRUE 1775862477 uids eyJ0ZW1wVUlEcyI6eyJhZG54cyI6eyJ1aWQiOiIxNDQ2NjY0NjMzMDYyNDU1NzM4IiwiZXhwaXJlcyI6IjIwMjYtMDEtMjRUMjM6MDc6NDkuMDk0MTEwNzE1WiJ9LCJhbXgiOnsidWlkIjoiNjY5NGRlM2YtYTRlNC00MTUzLWJlOTAtMzgwNzBmMzIyYzc2IiwiZXhwaXJlcyI6IjIwMjYtMDEtMjRUMjM6MDc6NTcuMzI4NDE3MDQ0WiJ9LCJydWJpY29uIjp7InVpZCI6IjEiLCJleHBpcmVzIjoiMjAyNi0wNC0xMFQyMzowNzo0N1oifSwiY29ubmVjdGFkIjp7InVpZCI6IjEiLCJleHBpcmVzIjoiMjAyNi0wNC0xMFQyMzowNzo1N1oifX19
|
||||
.adnxs.com TRUE / TRUE 1775862514 XANDR_PANID PCf2dRo2AFUKrIDqTJhluM3eM1XLRFlhDROSCoEjPO_Sw3m5nzC-ztQr0_2_onNy6e4tHgdHVNekMcT6peC1QxLqYdSVViNIymGcFz_JA7k.
|
||||
support.squarespace.com FALSE / FALSE 1786028735 SQSP_HarveyDent {%22aus_live_chat%22:{%22variant%22:%22variant%22%2C%22when%22:%22Wed%2C%2002%20Jul%202025%2015:05:35%20GMT%22}%2C%22autologin-qa%22:{%22variant%22:%22variant%22%2C%22when%22:%22Wed%2C%2002%20Jul%202025%2015:05:35%20GMT%22}%2C%22fullstory_2024%22:{%22variant%22:%22control%22%2C%22when%22:%22Tue%2C%2001%20Jul%202025%2023:57:21%20GMT%22}}
|
||||
.www.ten31timestamp.com TRUE / TRUE 1783259137 ab_experiment_sampled %22false%22
|
||||
.www.ten31timestamp.com TRUE / TRUE 1783259137 ab_testing_id %224951d750-8a99-4bec-be9f-70654cb5e528%22
|
||||
.lynalden.com TRUE / FALSE 1786460292 _ga GA1.2.1028841246.1751900292
|
||||
.lynalden.com TRUE / FALSE 1786460293 _ga_L92TPRGR2X GS2.2.s1751900292$o1$g0$t1751900292$j60$l0$h0
|
||||
.www.lynalden.com TRUE / TRUE 1783436299 __stripe_mid b632f803-daa5-47b6-ac31-677c6d2eaa3c9f9398
|
||||
www.gentexcorp.com FALSE / TRUE 1783461745 CookieConsent {stamp:%27K6r5zFH9mn5JntJlZZFzhGRJN4b9yBifDOZtJtW14s06elm6tuanLA==%27%2Cnecessary:true%2Cpreferences:false%2Cstatistics:false%2Cmarketing:false%2Cmethod:%27explicit%27%2Cver:1%2Cutc:1751925745079%2Cregion:%27us-47%27}
|
||||
.fliphtml5.com TRUE / FALSE 1786485759 first_visit_channel_source {"channel":"","referer":"https://www.gentexcorp.com/ops-core/","page":"https://online.fliphtml5.com/usalo/ngjl/","time":1751925758501,"uuid":"1321c34c-fe88-41b9-918d-bdc107547787"}
|
||||
.fliphtml5.com TRUE / FALSE 1786485759 _ga GA1.1.2038386891.1751925759
|
||||
.fliphtml5.com TRUE / FALSE 1786485760 _ga_DQQGBZ508R GS2.1.s1751925758$o1$g0$t1751925760$j58$l0$h0
|
||||
www.atomicdefense.com FALSE / FALSE 1783461903 localization BR
|
||||
www.atomicdefense.com FALSE / FALSE 1783461791 po_visitor m8eTuYuxWK1s
|
||||
www.atomicdefense.com FALSE / FALSE 1783461903 _pin_unauth dWlkPVptSTNNak5tWkRrdE1tUXpNQzAwWmpRMExUbGpOV1l0Tm1Zd1lXTTJOVGhqTW1ObQ
|
||||
www.atomicdefense.com FALSE / FALSE 1783461900 AMP_9bdc728a74 {"deviceId":"f06d75df-1f90-4871-83ca-407a640705fa","sessionId":1751925900780,"lastEventTime":1751925900785,"optOut":false}
|
||||
www.atomicdefense.com FALSE / FALSE 1783461903 mktz_client %7B%22is_returning%22%3A0%2C%22uid%22%3A%2219038728291293545260%22%2C%22session%22%3A%22sess.2.1065091378.1751925789881%22%2C%22views%22%3A4%2C%22referer_url%22%3A%22https%3A//www.google.com/%22%2C%22referer_domain%22%3A%22www.google.com%22%2C%22referer_type%22%3A%22organic%22%2C%22visits%22%3A1%2C%22landing%22%3A%22https%3A//www.atomicdefense.com/collections/ops-core%3Fsrsltid%3DAfmBOooj_64xdS_VznDSwAnnBIus-V5EU_sm13jPgwNFmBugUYJYlVPZ%22%2C%22enter_at%22%3A%222025-07-7%7C17%3A3%3A9%22%2C%22first_visit%22%3A%222025-07-7%7C17%3A3%3A9%22%2C%22last_visit%22%3A%222025-07-7%7C17%3A3%3A9%22%2C%22last_variation%22%3A%22%22%2C%22utm_source%22%3Afalse%2C%22utm_term%22%3Afalse%2C%22utm_campaign%22%3Afalse%2C%22utm_content%22%3Afalse%2C%22utm_medium%22%3Afalse%2C%22consent%22%3A%22%22%2C%22device_type%22%3A%22desktop%22%2C%22id_website%22%3A%2222272%22%7D
|
||||
www.atomicdefense.com FALSE / FALSE 1786485904 __kla_id eyJjaWQiOiJOVEUxTWpKbVpqQXRaV0kzTWkwMFltVmlMV0UzTXpBdFpqazFaamMzWW1Sa05tUmkiLCIkcmVmZXJyZXIiOnsidHMiOjE3NTE5MjU3OTIsInZhbHVlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8iLCJmaXJzdF9wYWdlIjoiaHR0cHM6Ly93d3cuYXRvbWljZGVmZW5zZS5jb20vY29sbGVjdGlvbnMvb3BzLWNvcmU/c3JzbHRpZD1BZm1CT29val82NHhkU19Wem5EU3dBbm5CSXVzLVY1RVVfc20xM2pQZ3dORm1CdWdVWUpZbFZQWiJ9LCIkbGFzdF9yZWZlcnJlciI6eyJ0cyI6MTc1MTkyNTkwNCwidmFsdWUiOiJodHRwczovL3d3dy5nb29nbGUuY29tLyIsImZpcnN0X3BhZ2UiOiJodHRwczovL3d3dy5hdG9taWNkZWZlbnNlLmNvbS9jb2xsZWN0aW9ucy9vcHMtY29yZT9zcnNsdGlkPUFmbUJPb29qXzY0eGRTX1Z6bkRTd0FubkJJdXMtVjVFVV9zbTEzalBnd05GbUJ1Z1VZSllsVlBaIn19
|
||||
.atomicdefense.com TRUE / FALSE 1783461789 ig-id ig_5776dfedafb4fbfa5d8a0463ec428fdb482d
|
||||
.atomicdefense.com TRUE / FALSE 1783461789 ig-fv 1751925789909
|
||||
.atomicdefense.com TRUE / FALSE 1783461904 ig-vars {%22redirectedFrom%22:%22%22}
|
||||
.atomicdefense.com TRUE / FALSE 1783461905 _tracking_consent 3.AMPS_USTN_f_f_zab7AzwiQy-Q8yLtLVc7Sg
|
||||
.atomicdefense.com TRUE / FALSE 1783483509 _shopify_y 451263ce-612e-4c39-b0fe-443739bf2b16
|
||||
.atomicdefense.com TRUE / FALSE 1783461792 _clck ocpdsc%7C2%7Cfxe%7C0%7C2014
|
||||
.atomicdefense.com TRUE / FALSE 1786485904 _ga GA1.1.1985663682.1751925793
|
||||
.atomicdefense.com TRUE / FALSE 1783461904 ig-pv 4
|
||||
.atomicdefense.com TRUE / FALSE 1785621904 _uetvid 2d99def05b7e11f095a86b06a58774de
|
||||
.atomicdefense.com TRUE / FALSE 1786485971 _ga_DR9XYZYM0N GS2.1.s1751925793$o1$g1$t1751925970$j23$l0$h0
|
||||
.atomicdefense.com TRUE / FALSE 1786485971 _ga_RXXREL5ZDN GS2.1.s1751925793$o1$g1$t1751925970$j60$l0$h0
|
||||
.shop.app TRUE / TRUE 1783461790 _shop_app_essential :AZfm6hWDAAEA2lpbeXDvhGPE2CP5hEllSYSKvAUDHudOlhmgIiEVVnPR0SjK8iStsKARIED0vfI:
|
||||
shop.gentexcorp.com FALSE / TRUE 1786485991 fornax_anonymousId 43a7fe87-4464-4364-a9b3-d09c4d9bc2c1
|
||||
imgs.signifyd.com FALSE / TRUE 1786485792 thx_guid 02ee0705746ea94abf905302f905850a
|
||||
imgs.signifyd.com FALSE / TRUE 1786485989 tmx_guid AAyzkeJccLt_C_o4kB4ST4GaYVbg5NQoZFdThM_wef9bqxO5rVGOJT_lY3ZajVHU_V0vj2k-mbu90T98Bfdkh2oEoUFhdQ
|
||||
.www.atomicdefense.com TRUE / FALSE 1785621904 _ttp 01JZKEM7EB58RNXBEDDN22T99Y_.tt.0
|
||||
.www.atomicdefense.com TRUE / FALSE 1785621904 ttcsid_C5D3RI94DV8CDK843CH0 1751925792247::ghM8Tb_9JiqcUXeKz3dd.1.1751925904202
|
||||
.www.atomicdefense.com TRUE / FALSE 1785621904 ttcsid 1751925792260::RdbnOzqaRoJcPIMjCNiQ.1.1751925904263
|
||||
.imgflip.com TRUE / FALSE 1786505380 _ga GA1.1.1468374004.1751944562
|
||||
.imgflip.com TRUE / FALSE 1786504563 _lc2_fpi 9099df4a8854--01jzm0h28krqc9vshh3xhn8bkn
|
||||
.imgflip.com TRUE / FALSE 1786504563 _lc2_fpi_meta %7B%22w%22%3A1751944562963%7D
|
||||
.imgflip.com TRUE / TRUE 1783480563 connectId {"ttl":86400000,"lastUsed":1751944563314,"lastSynced":1751944563314}
|
||||
.imgflip.com TRUE / TRUE 1783480661 _au_1d AU1D-0100-001751944563-69KY1P7C-GVCX
|
||||
.imgflip.com TRUE / FALSE 1785622660 cto_bundle oUv1S19mSmowTTh0d2pqaWpkb1dmYTVobmdNdVd0aWFMNThOd0lzajdSTDBSOWRaTUI3ZWVrMzQxeCUyQnhvVUoxNkRXOGNvM3VDNDZySFBoeiUyQm5QQnFqT3duaXZhS0Q3WUR5eWp4bjczMWZXSVR4RUVDVjVaYWhyVUhGSzRCb1ozd1VpY2xRMGRkVGVtNGZOVDdIWm5vdUI0cUMlMkZjdDJWMGtMJTJGNlU0YlA2WFlmJTJCb1UySUR3cFZuZmF6JTJCeXhYYXhPeUY4d05OYXZjVE12V1JLV3NIeWVsNUVQQWt3JTNEJTNE
|
||||
.imgflip.com TRUE / FALSE 1785622660 cto_bidid Lw_CZl95T0FzZWhSd3oxRnNXa0FvcDU2TnZDY3l0S0FLVkJHZURTRiUyQnY4aWpWeiUyQm5CTkpUdXpMQ29lZTBXbk0zSjkzekJCbmtDb2Q0dE42YjE3WTdPRzByMDZHOEx6ZldnZzhSSUVhRlVpb21pc2E0Y2dLanNUVXhxc2R4dWI0M1g3VGRTRE90MjN1WUNwN3psaXpqdEU0dUZRJTNEJTNE
|
||||
.imgflip.com TRUE / TRUE 1785640563 __gads ID=be74fbe2c6af3547:T=1751944563:RT=1751945371:S=ALNI_Majida08QPOx0983ktIinyR_WTtvw
|
||||
.imgflip.com TRUE / TRUE 1785640563 __gpi UID=000010f862a6cf50:T=1751944563:RT=1751945371:S=ALNI_MZePD2Obp6lMmzFkvBjgc8EFVzWug
|
||||
.imgflip.com TRUE / FALSE 1786505372 _ga_DCRTFFEBRL GS2.1.s1751944562$o1$g1$t1751945372$j60$l0$h0
|
||||
.imgflip.com TRUE / FALSE 1786505380 _ga_X8YQQMPY4Q GS2.1.s1751944562$o1$g1$t1751945380$j60$l0$h0
|
||||
.imgflip.com TRUE / FALSE 1786505380 _ga_FVWZ0RM4DH GS2.1.s1751944594$o1$g1$t1751945380$j60$l0$h0
|
||||
imgflip.com FALSE / FALSE 1785640563 usprivacy 1---
|
||||
imgflip.com FALSE / FALSE 1786504661 ad_clicker false
|
||||
imgflip.com FALSE / FALSE 1783480593 mako_fpc_id 3738993d-cd36-4677-b646-6fc049347db8
|
||||
.yahoo.com TRUE / TRUE 1799644078 A3 d=AQABBLnFMmUCEMk1D1H8-MekCRhtMCBNsz4FEgEBCAGBL2dXZ9xR0iMA_eMDAAcIucUyZSBNsz4&S=AQAAAoKPGn6r5rWbaNAGTE52Z1o
|
||||
.seedtag.com TRUE / TRUE 1799622514 st_uid 0197e809-1d28-76fe-bd2e-2a8367a9b191
|
||||
.seedtag.com TRUE / TRUE 1799190473 st_cs l+EQxuppf4rbMmxYXoBW58T59pDkRx2pDuf/17SALU9Kr4IZJN0cUVL9qSFzxTAd6H7BITeXLEgmthJP6fQVva7CVfG+zgCuqsD8N5JSlleiKNVn8TIyfg5O8p0Ff5DWk18CTQyrN1LPhrZQsSU26fG2cTnsjPdRDuSZqm3jHyGtWResS77PKvj5IR9wv7KBD9lfFPw+rcj7MYK14NZNBH9zDwhlZ6CQiHVH/gB40SyhhlvVnxvcGGyD2zdLMjJM94XMjgx0JPFSyGm6M1LjRGLCBip0RzrA8awS9XfgBBXD4jkuHKmqnkIY7xibjo/Ef1EjhGjXZ87kZ3+vgJhzGpz+MqoPTBm7G83cnoW8vKyBKWMpPolYLzdcmCokXd0JaiY5HjG/MCVxt21HD6wxD5W8eplRV+Xnf0NNqyhjdw0GVCwnqsOCz+jA8a2vMQJb+1aV3ZRIeIrzFzdAmb9VF4OO3Sf9HsM+Gw/gGcK5cyRXNyNPCh7Bf5DLNA/rVVoHngxiAPkZM/0a5xpk1VxRNNrdFNAXlVHBGMQqQrw2AUvdAZlpdqd3GN+tqhVA5DZTTODKPtehdNzRfse84/OFrTIb77P5m0ZjEOMsRvUNZ/JHJH0dBNWPLTJZ2vQ2GjhW4zX5tIaAAbPjVavGlHCYzbQBbw2rAzVhmJklTv03qxGlunzkDQTPzcx3Tj+m4f2y9x/Kbk3bX8AVX84Se59+swq+7PyNEaqydy37toP4jxkuQoHzVofwsxjsLFA6rwwUN4eTcrg5acgNRAl5VpTv7fi8B3UBXUnAThL1TV+WBBqX25UXrvC5b7lVUIYrpmwlzBkC4t72H2bW7UHw7YcLxLfpcJnP91i+qE0j5Bh0R3A1GV5TXKYU6G83s5Kw7F8s6hx8uL0Xeqz9iOf+Gwk8sr+gk6Hx8SqdTIzbIYDBjYXUR/oIC5hQa7/h0Sg3YldN5JyPc1UWz6GGHtOJknxGmsgfsySZ2KZR9P1j8hF2pnmF1IBV0ijc48jSMVH18gbmB9j0Rqb+QCLFnDa0+eo7m8SMc6Go4Ir3o4DTS4d/WUx7o0+jnVlqZg7BWkQdb2DCuyxTzW+e607oasZCQYzaYpNwyOPZiBbDHu20PMIg2XedEn6dZCM0TKI11NcF2bdI
|
||||
.seedtag.com TRUE / TRUE 1799190473 st_csd 1768086473030:1768086473030
|
||||
.ymmobi.com TRUE / TRUE 1783048602 ym_user_cookie ym_user_5b605628-abd0-48fd-bd12-83c5c527fa56
|
||||
.imageresizer.com TRUE / TRUE 1783480605 _au_1d AU1D-0100-001751944605-941OR5IA-XZDN
|
||||
.imageresizer.com TRUE / TRUE 1785640604 __gads ID=1f9e426ea177e36f:T=1751944604:RT=1751944604:S=ALNI_MbPQ8YWwfAMnZDnSpZTK-1tzXkpSQ
|
||||
.imageresizer.com TRUE / TRUE 1785640604 __gpi UID=000010f8629bfb1f:T=1751944604:RT=1751944604:S=ALNI_MannLbLSR4mPPaI59X6gzoqBfXaPQ
|
||||
.imageresizer.com TRUE / FALSE 1783480605 FCNEC %5B%5B%22AKsRol_EONZyLR1QTUgle0ZVzM-n9ByfL6ADfltvoktmT5_GjgRq-XCG1s0xa-hgfjTd-uRi6s_LNCs0l7GI-7ZPGJMD_EwaEXhwaCHyS6nynf6A5dCwHjop7b5xXj7GoDFI1NQZ3SHBWtd-UXkk7eiMAC3kWCCzlA%3D%3D%22%5D%5D
|
||||
.imageresizer.com TRUE / FALSE 1786504653 _ga_HKYMVDPKL5 GS2.1.s1751944604$o1$g1$t1751944652$j12$l0$h0
|
||||
.imageresizer.com TRUE / FALSE 1786504653 _ga_FVWZ0RM4DH GS2.1.s1751944652$o1$g0$t1751944652$j60$l0$h0
|
||||
.imageresizer.com TRUE / FALSE 1786504653 _ga GA1.1.375673278.1751944604
|
||||
.dotomi.com TRUE / TRUE 1802214483 DotomiUser 735907388364061728$0$1937005452$0$1
|
||||
.dotomi.com TRUE / TRUE 1802214483 receive-cookie-deprecation 1
|
||||
.tremorhub.com TRUE / TRUE 1786505372 tv_UIGL CAESEASjkMgMQrOFLnFB39UE0C4
|
||||
.substack.com TRUE / TRUE 1783516203 ab_experiment_sampled %22false%22
|
||||
.substack.com TRUE / TRUE 1783893441 ab_testing_id %2244509386-1a6b-42f4-b509-ab1db0e27257%22
|
||||
.substack.com TRUE / FALSE 1783893441 ajs_anonymous_id %227bb0425f-0f94-4e6c-8063-0f20a54752e2%22
|
||||
.substack.com TRUE / TRUE 1783516203 cf_clearance aUh6OlZdUfcR60RwE6JMZek1WPAqCm6uDxKFKqPiXog-1751980203-1.2.1.1-kjJYlHkQzvgVBAGX3gDpDTsZ1fH4YGoYbW5gPEh9PL_0ZxL5XuPCe84MnpCCiOgM6PkhHjQwx19CErUhQFVdrbpTu2rhi_uCSi_90idaOy4otuMFWzb3EEao5KHcecVNPa2OK1j4pzW2mgsYrREEItKlOZYEHiWQX2H7KmI25k2au7PEVvLyHuhpETFJ8QXFkezJns.8Foz5YEC6adgVgoEcTN5Ey6qyZmlGaJdPcbQ
|
||||
bitvocation.substack.com FALSE / FALSE 1783516203 ajs_anonymous_id %227bb0425f-0f94-4e6c-8063-0f20a54752e2%22
|
||||
bitvocation.substack.com FALSE / FALSE 1786540205 intro_popup_last_hidden_at 2025-07-08T13:10:04.898Z
|
||||
.spotify.com TRUE / TRUE 1784809599 sp_t 9b0c39cb0a61c277ad5448d840cfd76f
|
||||
.onrampbitcoin.com TRUE / FALSE 1786540591 _lc2_fpi 596329408dff--01jzn2whhcz8c8ajjthcwmkdtc
|
||||
.onrampbitcoin.com TRUE / TRUE 1783084591 _reb2buid 8bd9bd84-1391-4e3d-846c-328b0c081882-1751980590774
|
||||
.onrampbitcoin.com TRUE / FALSE 1786540591 _li_ss CgA
|
||||
.airtable.com TRUE / TRUE 1783633552 brw brw4smjnDVd8Cinv4
|
||||
.airtable.com TRUE / FALSE 1785793501 _uetvid f78798d05d0d11f08a6705efe43f47fe
|
||||
.airtable.com TRUE / FALSE 1783633501 _clck iakk65%7C2%7Cfxg%7C0%7C2016
|
||||
.airtable.com TRUE / FALSE 1786657502 _ga GA1.1.882492552.1752097502
|
||||
.airtable.com TRUE / FALSE 1786657502 _ga_VJY8J9RFZM GS2.1.s1752097501$o1$g0$t1752097501$j60$l0$h0
|
||||
.airtable.com TRUE / FALSE 1786657502 __q_state_bhFVoN1cyFKKDaNW eyJ1dWlkIjoiMzkxNzJkMjUtZjk5OS00YjZhLTljYmUtNTYwNTdiNjQ2YjEyIiwiY29va2llRG9tYWluIjoiYWlydGFibGUuY29tIn0=
|
||||
.airtable.com TRUE / TRUE 1783719903 acq eyJhY3F1aXNpdGlvbiI6Ilt7XCJwbGF0Zm9ybVwiOlwiZGVza3RvcFwiLFwib3JpZ2luXCI6XCJscFwiLFwidG91Y2hUaW1lXCI6XCIyMDI1LTA3LTA5VDIxOjQ1OjAxLjQzMFpcIixcInJlZmVycmVyXCI6XCJodHRwczovL3d3dy5nb29nbGUuY29tL1wiLFwidXRtX3NvdXJjZVwiOlwiZ29vZ2xlXCIsXCJ1dG1fbWVkaXVtXCI6XCJwYWlkc2VhcmNoXCIsXCJ1dG1fdGVybVwiOlwiYWlydGFibGVcIixcInV0bV9jYW1wYWlnblwiOlwiZGVtYW5kX2JyX2JyYW5kX2FsbF91c19lblwiLFwidXRtX2V4dHJhMlwiOlwiOTM2NDA3NjkxXCIsXCJ1dG1fZXh0cmE1XCI6XCJrd2QtMzI1Mjg5MzIzMTk0XCIsXCJ1dG1fZXh0cmE4XCI6XCJjXCIsXCJ1dG1fZXh0cmExMFwiOlwiNDc3MzU2MDA1NThcIixcInV0bV9leHRyYTlcIjpcIkVBSWFJUW9iQ2hNSTctang1OS13amdNVnhrN19BUjBjQWpXWkVBQVlBU0FBRWdMUTRfRF9Cd0VcIn0se1wicGxhdGZvcm1cIjpcImRlc2t0b3BcIixcIm9yaWdpblwiOlwibG9naW5cIixcInRvdWNoVGltZVwiOlwiMjAyNS0wNy0wOVQyMTo0NTowMi43OTdaXCIsXCJyZWZlcnJlclwiOlwiaHR0cHM6Ly93d3cuYWlydGFibGUuY29tL2xwL2FpLXBzdS1wbHA/dXRtX3NvdXJjZT1nb29nbGUmdXRtX21lZGl1bT1wYWlkc2VhcmNoJnV0bV9leHRyYTU9a3dkLTMyNTI4OTMyMzE5NCZ1dG1fZXh0cmEyPTkzNjQwNzY5MSZ1dG1fZXh0cmExMD00NzczNTYwMDU1OCZjcmVhdGl2ZT03MTk0ODYyMDM5MDgmdXRtX2V4dHJhOD1jJnV0bV90ZXJtPWFpcnRhYmxlJnV0bV9jYW1wYWlnbj1kZW1hbmRfYnJfYnJhbmRfYWxsX3VzX2VuJmdhZF9zb3VyY2U9MSZnYWRfY2FtcGFpZ25pZD05MzY0MDc2OTEmZ2JyYWlkPTBBQUFBQUR6UnFuVXNPTWY4OFlXQ3hmNmlVMUNkcXZ6VXomZ2NsaWQ9RUFJYUlRb2JDaE1JNy1qeDU5LXdqZ01WeGs3X0FSMGNBaldaRUFBWUFTQUFFZ0xRNF9EX0J3RVwifV0ifQ==
|
||||
.airtable.com TRUE / TRUE 1783719903 acq.sig VbCJhMJQ8qvQpqGFONOWbN1OXlApNf5ntop0TkAw-80
|
||||
.airtable.com TRUE / FALSE 1783633503 OptanonConsent isGpcEnabled=0&datestamp=Wed+Jul+09+2025+16%3A45%3A03+GMT-0500+(Central+Daylight+Time)&version=202407.1.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=abc3b4d9-ab2a-43a3-b283-c4af636ff8e5&interactionCount=1&isAnonUser=1&landingPath=NotLandingPage&groups=C0001%3A1%2CSSPD_BG%3A1%2CC0004%3A1%2CC0002%3A1%2CC0007%3A1%2CC0003%3A1&AwaitingReconsent=false
|
||||
.airtable.com TRUE / FALSE 1783633503 _pxvid f8799d0c-5d0d-11f0-b579-e0c8bc5ee247
|
||||
airtable.com FALSE / TRUE 1783719901 __Host-airtable-session eyJzZXNzaW9uSWQiOiJzZXN0TU1qR0R2VmxIZm5BMyIsImNzcmZTZWNyZXQiOiIzVDJRVUhfQXJCd0ZiOVRHZ3E5aElsX0QifQ==
|
||||
airtable.com FALSE / TRUE 1783719901 __Host-airtable-session.sig Aidk0OW2vbUxWfZB4R4MhZaWcq78REvJPHO8MMRLxI0
|
||||
www.airtable.com FALSE / TRUE 1786657501 _gd_visitor cfe31e24-0577-4f24-8a7b-c5b5b543d807
|
||||
.www.o-big.com TRUE / TRUE 1786659845 svSession 0fd5e4906b7339cf9bde249633a18234cf868b613a67599fb1325cf6699014e5c326ac79c994a282767ff1780b559f631e60994d53964e647acf431e4f798bcdb7ea6cd9965668a1c08575c953936cf7a269ffc58bff5c078e08f5ac4e0c9f3523ed3cd3d08cd0d5bf5f8249d5cb460e97486947151a2d4b846e328f0b3a965bfc47f77fd29db05c561cd0b5dc7cb10e
|
||||
www.capitalcreek.com FALSE / FALSE 1786662356 ss_cvr 9a009276-bc2c-42f1-ae1f-bd774a7e367a|1752102341467|1752102341467|1752102341467|1
|
||||
.phantombuster.com TRUE / FALSE 1786912344 _ga GA1.1.952538975.1752352344
|
||||
.phantombuster.com TRUE / FALSE 1783888344 amp_e1d871 17515780722794205086972709266.b3JnXzU0MDY4OTQ0Njk5OTgwNzg=..1j005diff.1j005diff.1.0.1
|
||||
.phantombuster.com TRUE / FALSE 1786912356 _ga_1J42NVR091 GS2.1.s1752352344$o1$g1$t1752352355$j49$l0$h0
|
||||
.dropbox.com TRUE / TRUE 1787106780 locale en
|
||||
.dropbox.com TRUE / TRUE 1784082806 t Ro6TSx0EmgdOtX2d9pqOd4IT
|
||||
www.dropbox.com FALSE / TRUE 1787106780 gvc MzA4NDYxNDYwOTg2NDU2ODM3NTY5MjU1OTU4OTMzMzkyODY0MDM5
|
||||
www.dropbox.com FALSE / TRUE 1784082806 __Host-js_csrf Ro6TSx0EmgdOtX2d9pqOd4IT
|
||||
.x.com TRUE / TRUE 1787107244 guest_id_marketing v1%3A175254724429867078
|
||||
.x.com TRUE / TRUE 1787107244 guest_id_ads v1%3A175254724429867078
|
||||
.x.com TRUE / TRUE 1787107244 guest_id v1%3A175254724429867078
|
||||
.x.com TRUE / TRUE 1787107244 personalization_id "v1_6oYA/pddvCo/znTfM2ySMg=="
|
||||
announcekit.app FALSE / TRUE 1784087903 ak_eu_41U9JC eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyIkIjpbMSwiODEyODM0MzEzODYwMjEzMS1wcm9kIl0sImlhdCI6MTc1MjU1MTkwM30.zHj6WLSLJK5OEX4a5WYD2vG75uxC24iffpeLzr47_FI
|
||||
.arkm.com TRUE / FALSE 1784089797 mp_f32068aad7a42457f4470f3e023dd36f_mixpanel %7B%22distinct_id%22%3A%20%22%24device%3A1980c58b88316d-00fd236b85478a-17525636-1fa400-1980c58b88316d%22%2C%22%24device_id%22%3A%20%221980c58b88316d-00fd236b85478a-17525636-1fa400-1980c58b88316d%22%2C%22%24initial_referrer%22%3A%20%22https%3A%2F%2Fprimal.net%2F%22%2C%22%24initial_referring_domain%22%3A%20%22primal.net%22%2C%22__mps%22%3A%20%7B%7D%2C%22__mpso%22%3A%20%7B%22%24initial_referrer%22%3A%20%22https%3A%2F%2Fprimal.net%2F%22%2C%22%24initial_referring_domain%22%3A%20%22primal.net%22%7D%2C%22__mpus%22%3A%20%7B%7D%2C%22__mpa%22%3A%20%7B%7D%2C%22__mpu%22%3A%20%7B%7D%2C%22__mpr%22%3A%20%5B%5D%2C%22__mpap%22%3A%20%5B%5D%7D
|
||||
.arkm.com TRUE / FALSE 1787113799 _ga GA1.1.1405382360.1752553799
|
||||
.arkm.com TRUE / FALSE 1784089799 _clck yis5e9%7C2%7Cfxm%7C0%7C2022
|
||||
.arkm.com TRUE / FALSE 1787113809 _ga_K3BXC51SZE GS2.1.s1752553798$o1$g1$t1752553809$j49$l0$h0
|
||||
.arkm.com TRUE / FALSE 1787113809 _ga_P74N755GGG GS2.1.s1752553799$o1$g1$t1752553809$j50$l0$h0
|
||||
www.clarity.ms FALSE / TRUE 1784089799 CLID 3796f63d2e084a1099127441ee73559a.20240224.20260715
|
||||
riverside.fm FALSE / TRUE 1787164202 fullstoryDisabled false
|
||||
riverside.fm FALSE / FALSE 1784140202 language en
|
||||
.techcrunch.com TRUE / FALSE 1787668441 _lc2_fpi 97c377c895b4--01k0ppft76z9bxs29b449re4k1
|
||||
.techcrunch.com TRUE / FALSE 1787668441 _lc2_fpi_meta %7B%22w%22%3A1753108441318%7D
|
||||
.techcrunch.com TRUE / TRUE 1787236442 _awl 2.1753108442.5-4718d52d8d3ff7e48da0c74e99d3637d-6763652d75732d6561737431-1
|
||||
.royalcaribbean.com TRUE / FALSE 1784673342 rwd_id 863febde-c986-4dbf-bfaf-3013289b94f2
|
||||
.royalcaribbean.com TRUE / TRUE 1784673135 BVBRANDID ad90f986-2e00-4e20-b3dc-2f11159e449c
|
||||
.royalcaribbean.com TRUE / FALSE 1784673135 crl8.fpcuid 92329951-c9c1-4190-90a4-3598a26f3afe
|
||||
.royalcaribbean.com TRUE / TRUE 1784807731 _abck F108A0B9EC005650B661BF9BB01E7D19~0~YAAQxB82F8Uusw2YAQAAwIMjNw7zxV37FmFRxuYUmdPLtoXWoJcetrWoLyngJEXmdAvZRLJ3G8bUCK/9WC1A83/xsytYK/VjD0VDLgtX6WMJupvmzPjR/NKzWFWNvcdtWyHy/viOAR1lY+TUp4hJJOvvvaQg5YWJQhTJketokwwY5LujWHmkCS62dIPHsRKIXzSB3di8GjJUJT10IXUdLwQTKdtBNuRabiqewxVQ2luIxxBji809V9VIsr0PtK2OZt8gWAyiyOUDsusB0reCIQXFMFv1z7MfvJnp5WNCHgt2q7+gMVPwt8Kl2VSOckIcuclbQK110QY+XuD8xHy1Z9N7HcfAr4c7GvrUSaR6RUqHRFZ2RTZKeUUl+urKkXreeiOpWfuGOZJnh3GBblgbnPR7SCB17e4JBGBKPoZUBxbn/fUNDTfO51UmMIyU0bqgAku7TrogzHb7RW2L+/DtTjdkbNAHvS2Kjx4KaqTY3UgqGVpYfHXb+HW7Mq3qsCpNXm+gPGhPRuKWgrR5WEzfRZ30R/GPyfWG3RuHCe3DkaAawSt/Z2zeFaIsQIsJ6LmPgDdp0krG6sOWsELRj/09lhSF017IcDkrvRBkhpmQOOnEhHBv0E15VsnoBEWbjeZG54PxNW0=~-1~-1~1753275331
|
||||
.affirm.com TRUE / TRUE 1787697151 tracker_device 4292def8-15ab-4237-b3ca-9f5e52246878
|
||||
.affirm.com TRUE / TRUE 1787697151 t_v2_s IjQyOTJkZWY4LTE1YWItNDIzNy1iM2NhLTlmNWU1MjI0Njg3OCI.G2BRfw.kUXQa7Q6O69gRkS5dOf07g_tjjU
|
||||
.affirm.com TRUE / TRUE 1787697151 3060738.3440491 4292def8-15ab-4237-b3ca-9f5e52246878
|
||||
www.affirm.com FALSE / TRUE 1787697151 session eyJfcGVybWFuZW50Ijp0cnVlfQ.G2BRfw.2iT6h9nSbIrnYiDK8QzBXBNu9rg
|
||||
www.royalcaribbean.com FALSE / FALSE 1787697365 checkout_continuity_service 4292def8-15ab-4237-b3ca-9f5e52246878
|
||||
www.royalcaribbean.com FALSE / FALSE 1787697365 tracker_device 4292def8-15ab-4237-b3ca-9f5e52246878
|
||||
.www.royalcaribbean.com TRUE / FALSE 1784673365 OptanonConsent isGpcEnabled=0&datestamp=Mon+Jul+21+2025+17%3A36%3A05+GMT-0500+(Central+Daylight+Time)&version=202411.2.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=3f85f375-54ce-4137-8722-39c3b4977d19&interactionCount=1&isAnonUser=1&landingPath=NotLandingPage&groups=C0001%3A1%2CC0003%3A1%2CC0002%3A1%2CC0007%3A1%2CC0004%3A1&AwaitingReconsent=false&geolocation=%3B
|
||||
.www.royalcaribbean.com TRUE / FALSE 1784673365 OptanonAlertBoxClosed 2025-07-21T22:36:05.381Z
|
||||
panteracapital.com FALSE / FALSE 1784862486 cookielawinfo-checkbox-necessary yes
|
||||
panteracapital.com FALSE / FALSE 1784862486 cookielawinfo-checkbox-functional no
|
||||
panteracapital.com FALSE / FALSE 1784862486 cookielawinfo-checkbox-performance no
|
||||
panteracapital.com FALSE / FALSE 1784862486 cookielawinfo-checkbox-analytics no
|
||||
panteracapital.com FALSE / FALSE 1784862486 cookielawinfo-checkbox-advertisement no
|
||||
panteracapital.com FALSE / FALSE 1784862486 cookielawinfo-checkbox-others no
|
||||
.espn.com TRUE / FALSE 1788711177 SWID 1CF34069-B43A-481D-C820-B9858B640E40
|
||||
.espn.com TRUE / FALSE 1788711180 mbox session#b77414c80b6646a6a0cc0845b13a44bc#1754153040|PC#b77414c80b6646a6a0cc0845b13a44bc.34_0#1817395980
|
||||
.agi.cash TRUE / FALSE 1789382528 __gsas ID=6758cd34cb5426af:T=1755686528:RT=1755686528:S=ALNI_MZ-wFdtgNKLvbYZ4dowVyQMR64yFw
|
||||
agi.cash FALSE / FALSE 1787222528 pvisitor e5aff3ba-477f-40b9-b537-d738f686877a
|
||||
.archive.is TRUE / FALSE 1784477267 tmr_lvid 4d87e89d7858ef61d33e1fe99f47ac73
|
||||
.archive.is TRUE / FALSE 1784477267 tmr_lvidTS 1755706067933
|
||||
.mail.ru TRUE / TRUE 1787328588 VID 24Phk500X52Y0026Kk1Q01oY:::0-0-0-cae53fc-0-dc04c0c:CAASEKxMyii6AT78_-3NUPqD0UIaYHtsqvds-0kSklpezGsuCNzWPVpfXllbLL1vqX4f428ZW2vUxODue-givca9Uz03dLH8ZLOAeFiLjUWT2D7xIKjFSSw1mNF8GXEjOnpIeFEPmwLXqAyKewzaUgOzLS9SFg
|
||||
.riverside.com TRUE / TRUE 1787243494 ajs_anonymous_id 21dd7898-1bfc-402f-b77a-7b431fcb8478
|
||||
.riverside.com TRUE / TRUE 1787243494 cookiehub eyJhbnN3ZXJlZCI6ZmFsc2UsInJldmlzaW9uIjoxLCJkbnQiOmZhbHNlLCJhbGxvd1NhbGUiOnRydWUsImltcGxpY3QiOnRydWUsInJlZ2lvbiI6IkcwIiwidG9rZW4iOiJwanhpdlJGdGpCeWw5bE1UTUxpWHNac3hWTzREdnNXb2c0eWRlYUhZNENlcmgxcmdhWkhaWVFGa3BWN0JTd1JJIiwidGltZXN0YW1wIjoiMjAyNC0wNC0xNlQxNzo1OTo1NC4wNTdaIiwiYWxsQWxsb3dlZCI6dHJ1ZSwiY2F0ZWdvcmllcyI6W10sInZlbmRvcnMiOltdLCJzZXJ2aWNlcyI6W119
|
||||
.riverside.com TRUE / TRUE 1787243494 _zitok e8af6ff1d02a6d1909bc1713290389
|
||||
.riverside.com TRUE / TRUE 1787243494 __stripe_mid 84ab569e-8d4f-4816-a632-04e6d62c32405c3e59
|
||||
.riverside.com TRUE / TRUE 1787243494 hubspotutk d4c3d9ccc190dc8a9c6c7ffef14b0996
|
||||
.riverside.com TRUE / TRUE 1787243494 _fbp fb.1.1731079730566.829343683934799639
|
||||
.riverside.com TRUE / TRUE 1787243494 _ga GA1.1.1848369474.1713290394
|
||||
.riverside.com TRUE / TRUE 1787243494 _clck viwp88%7C2%7Cfst%7C0%7C1849
|
||||
.riverside.com TRUE / TRUE 1787243494 fullstoryDisabled false
|
||||
.riverside.com TRUE / TRUE 1787243494 _gcl_au 1.1.1385786570.1755707485
|
||||
.riverside.com TRUE / TRUE 1787243494 __hstc 163253411.d4c3d9ccc190dc8a9c6c7ffef14b0996.1731079729263.1752604204117.1755707484497.7
|
||||
.riverside.com TRUE / TRUE 1787243494 __hssrc 1
|
||||
.riverside.com TRUE / TRUE 1787243494 _ga_PF9PK8DC9Z GS2.1.s1755707484$o7$g1$t1755707493$j51$l0$h1388164421
|
||||
.riverside.com TRUE / TRUE 1787243494 _rdt_uuid 1747764962554.d2f3b35b-0d3d-44cb-994a-6b01b09c67d9
|
||||
.riverside.com TRUE / TRUE 1787243494 _uetsid 1d1a53907de311f0943c870e79b8d202
|
||||
.riverside.com TRUE / TRUE 1787243494 _uetvid 21509ba0fc1b11ee99478f310d5b7258
|
||||
.riverside.com TRUE / TRUE 1787243494 __hssc 163253411.2.1755707484497
|
||||
.riverside.com TRUE / TRUE 1787243494 _dd_s rum
|
||||
riverside.com FALSE / TRUE 1787243494 language en
|
||||
.bbc.co.uk TRUE / TRUE 1788311620 ckns_policy 000
|
||||
.bbc.co.uk TRUE / TRUE 1788225215 ckns_privacy july2019
|
||||
.bbc.co.uk TRUE / TRUE 1791249209 ckns_sylphid OmbZGfsd9Pz9Yo_rfUvosfWknKRGe5bjx2yy809wxzg
|
||||
.bbc.co.uk TRUE / TRUE 1791249209 ckns_id eyJhYiI6Im8xOCIsInBhIjoiV0MyUiIsImVwIjp0cnVlLCJmaSI6eyJnYW0iOnsiaWQiOiIyNkJFMzY1MkZDMEU1NUM5NUZBN0ExQTA5NUFGMjdDQzEwRDIzNjczNDU0RDVDQjExOTJCNDczMDYxNjlCQzc4NTQyOENGQ0ZDQjU2MThFQkNGRUFBMzNGNDc1MkY2NTciLCJ2ZXJzaW9uIjoiYjk3MDk4MzItM2RhYS00ZTkyLWJjMDctMzg0MjA1YzIyZTQzIn0sInBpYW5vIjp7ImlkIjoieVNUQktyVlpLOTRuVnJDNzBNSUhjdlMwRXUzdVR6MnByd3hJcWM3UlFhbjRsUkZsUVN2elJhNThibnRSZFJ2ciIsInZlcnNpb24iOiI0NzFhMjM5YS1hYTNkLTQ5ZTYtOWIxZC1kNTcyNzhiNzkxMDgifSwiYWRhcHRlbXkiOnsiaWQiOiJGekFqQlBoWG5ydFQ0MEtENXhwdFg1K2ZlNDkzbXlpMmYxMTVDN0taTlV3RW5tSG5kNUxYZ2NUUFFrcVZTeEdDIiwidmVyc2lvbiI6IjFlZDZkOTM4LTM1NmEtNDU3MC1iMjZlLTU2NDg0NjcwNjhjYiJ9LCJnb29nbGUiOnsiaWQiOiJKcjQyVXZ3T1ZjbGZwNkdnbGE4bnpCRFNObk5GVFZ5eEdTdEhNR0ZwdkhoVUtNL1B5MVlZNjgvcW96OUhVdlpYIiwidmVyc2lvbiI6IjdjZDQ0MDJjLWViZjQtNDE5OC05MjliLWEyOWQ1ZmUwZTQxNiJ9LCJzdHVkaW9zX296b25lIjp7ImlkIjoiN3pWQkJWeE5HbEpqWUowbTFxcWFtWFpJMW5rYXFuK09XNExoNDkrOFpKeklQUlJGZU9ZWUNqeGl1SjJ4ZkF4SyIsInZlcnNpb24iOiI0OTNhNWI3Zi1jNjI1LTQ2ODctOTRmMi1lNWE1ZGIwOGM4OTkifSwicGVybXV0YXRpdmUiOnsiaWQiOiJUcitvU1B6RTVRNVh4ZVlQakFtdzNXaDNnMjlWbkRieHZScVJpdDZMbWM3UllGNHpGaWtEL1A1enNDSEFBZHl3IiwidmVyc2lvbiI6ImRkYjQ1ZGE3LWExNDQtNGUxNC04YjBlLTUwYjkyOTVjNzBmOSJ9fSwiZXYiOmZhbHNlLCJwbCI6ZmFsc2UsInBzIjoiaW1tUzFDRnpKMXg5VlRMQUx5aFJBeFpxSnkzZ3NPN1JSQm5MWGprX0JUMCIsImNsIjpmYWxzZSwiY2MiOiJnYiIsInJlYWxtIjoiLyIsInNlcy1leHAiOjE3NTY2OTAxMDkwMDAsImp3dC1leHAiOjE4MTk3NjEyMDkwMDAsInRrbi1leHAiOjE3NTY2OTU4MDgwMDAsInJ0a24tZXhwIjoxODE5NzYxMjA5MDAwfQ
|
||||
.bbc.co.uk TRUE / TRUE 1790903615 ckns_policy_exp 1788225215721
|
||||
.bbc.co.uk TRUE / TRUE 1788225216 ckns_iplayer_experiments {}
|
||||
.bbc.co.uk TRUE / TRUE 1788311620 ckns_explicit 1
|
||||
.bbc.com TRUE / TRUE 1788225190 ckns_mvt dc2f56e0-df7d-4cce-9e4b-dcf788e66fe4
|
||||
.bbc.com TRUE / TRUE 1788311620 ckns_policy 000
|
||||
.bbc.com TRUE / TRUE 1788311620 ckns_explicit 1
|
||||
.account.bbc.com TRUE / TRUE 1791249208 ckns_jwt eyJ0eXAiOiJKV1QiLCJjdHkiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ZXlKMGVYQWlPaUpLVjFRaUxDSnJhV1FpT2lKTk1VcDFVMHhGVlRkb2IwaG9NMVUwVlN0MmFHSnNiR1ZyU1VrOUlpd2laVzVqSWpvaVFURXlPRU5DUXkxSVV6STFOaUlzSW1Gc1p5STZJbEpUUVRGZk5TSjkuRjZFTDBMZFBiRkJwb245WmxUaXd0ZmI5aXFFOVFLaTdsQ2JRSWt0NzZBa2FqeXNjVzFsYUl1TGtmcmN1VHFicWJMWldTVHJPX0t3VTFaZ2JFOXgxaEtLRjQ5ZllKZ1BidXdoZ0Fha1lZWUlpSllnXy12M3ZwQXdmOTVwUFRnclkzeVItNFZJTGJldW1pS3Zvcy04blRpc3VPdzZydTBlVm5XemhscjVaTHdacDI0SXhHdUhOV3pkNEp0T1F2WUhuWDBxR2JsMUNDUElFTzFMX1FMZFhSOHRDMW9BQzJjd0FHYy1CY1lfOElfcGNqaHBmZGFGRklJaUprempaZ1Jad3pzZzhUOEVNSVgxYktJdlo3blZ1eDR0WWNTMnlfUU9NeU95aE1yUnMwQ2w1VG50S1A1cWFlUUdBY25SMmJwd19OUl9VTElMczFxQklDcTdGMjN0ZVhnLjJWOUVQdHFxcDByQjdQNGdkeXFVc0Euc0s3eXByMld5ZWJkNER2WEtaZkNWaVZudXROQTRHeXpZcjVKZXlwNExkWkkzVE9fWUNJN01LbXNjcVZtaGtqNjB1UVZvaXh1eFlmRURjZU1oOTdKRnhmT2hEM0M5aFZ5NS1mTmxzcmpZUjVqRFc2a3ZUWFlZbWd2ZjZPQVBsMFhJRUM3SEc3R2U5ckxBX3Z3REJKZ3FId1EzUWVxZ3ZqaWctTUJMQjNCNTM1Nlo1SDR5djBBVVVpRHY1MU8xLWNYT2dBLTF0QWpIaEhfWDhDM1dtY3VzS2dkSDZ0WHVxVV9hdWZ3MkVFQ3FwTmFSa0pGMnU4clNRTTlkczFNdW1PVzhGRmZHanljZjZ5bU1kZ1A0bU44SGR3SmdvQnpGU0NhckJNb0VZV2xsWjJZSnZuN3pxdl9uZnMwLUVrcnZVR1pZeEU3YnM2OEVtV3dFMnVMR3lxQkhXdlpmaExkOFc1ZGJ6blc5ZEJkMjdDS2paUElnazZDNk1vYWVhZHNiVF8yYUx1RjJFTVZRMGJ3TGpWcXdGQ1dVZ2ZaLWhubEVMWG81ZWlKbXpvS0gta2pGUTR0c3B4X2Q1TmRNSzFXMzRsSEF0SmQ0WmotMlVyclRrNlBTZWhvN0ZxTnJDaGRkR0pJMlRtQVpFY2pGcGNFeENtdW1XUHRrNWNScWJYaThETjBxdmZXb05BRG9DYTA5MWtEVEpBZXI5SVJfRFEzRmlUUVlzRHRybVFmRk5NdkJLbEF3Tk5wa09CamlGT1V4dGgxVXR3TGE5U0NsRWRXMXViV2R4UGFGckZzNHlURFoyTzA4ckdpdVJ6Nk1kUS5QVHZMcGpYU0lJYXRlYi11dS1scnJ3.fjjZwBvJzKI0vgBvZO6blAwtY0YJFjaRs8mio7nmpOE
|
||||
.session.bbc.co.uk TRUE / TRUE 1791249209 ckns_rtkn eyJ0eXAiOiJKV1QiLCJraWQiOiJFZ1VVKzhOaGFBWUtjNnlsb0NCcm5LUFRjZTg9IiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJiYzE5MzU0Yy04YmM2LTRhODYtODYyOC0yZTg2YjYxNzdmMDciLCJjdHMiOiJPQVVUSDJfU1RBVEVMRVNTX0dSQU5UIiwiYXV0aF9sZXZlbCI6MiwiYXVkaXRUcmFja2luZ0lkIjoiYTcyYWY3NjItZjMyNi00MGJjLWEwOTMtMjg2ZTIwNWYyMmE5LTExMjUxOTU2MSIsImlzcyI6Imh0dHBzOi8vYWNjZXNzLmFwaS5iYmMuY29tL2JiY2lkdjUvb2F1dGgyIiwidG9rZW5OYW1lIjoicmVmcmVzaF90b2tlbiIsImF1dGhNb2R1bGVzIjoiQkJDSURfSkRCQ19FTUFJTCIsInRva2VuX3R5cGUiOiJCZWFyZXIiLCJhdXRoR3JhbnRJZCI6IktuYXJhUVdkQUtJM05LWWNJaE1BRU92QlNRSSIsImF1ZCI6IkFjY291bnQiLCJhY3IiOiIwIiwibmJmIjoxNzU2Njg5MjA5LCJncmFudF90eXBlIjoiYXV0aG9yaXphdGlvbl9jb2RlIiwic2NvcGUiOlsiZXhwbGljaXQiLCJjb3JlIiwiaW1wbGljaXQiLCJwaWkiLCJ1aWQiLCJmaSIsIm9wZW5pZCIsImVkIl0sImF1dGhfdGltZSI6MTc1NjY4OTIwOCwicmVhbG0iOiIvIiwiZXhwIjoxODE5NzYxMjA5LCJpYXQiOjE3NTY2ODkyMDksImV4cGlyZXNfaW4iOjYzMDcyMDAwLCJqdGkiOiJBYm5zYml6aGt1UmRDbl96LVVvLUVRYUM5eDQifQ.eZRT1ndGRwxnsShBMfaE4EBO8k9mCxl2XGvadQcYlYLJZAojTbuOqeX8CXuU0Kr3FZjKmobzis570EwEVMRZmw
|
||||
www.benchmade.com FALSE / FALSE 1788736114 localization US
|
||||
www.benchmade.com FALSE / TRUE 1788736103 _shopify_essential :AZkhSEvUAAEA4RpevYPi8TQPeiP9QhKEUeiCqTaYc1dsi3rL20srm56ll2cYCcB6HjNfk9cIGFH0qm5_GPxfVNOjFN2nlK76b6vUQh3RDB3Qsc80ptryk1aj7UyjMo7UUNl869Rb64HXIbeaKeI:
|
||||
.benchmade.com TRUE / TRUE 1791760011 __eventn_id 05grsl4da0.1757200010
|
||||
.benchmade.com TRUE / TRUE 1788736011 ssUserId f6a10f03-956c-496d-a271-dd135d92dca4
|
||||
.benchmade.com TRUE / TRUE 1788736011 _isuid f6a10f03-956c-496d-a271-dd135d92dca4
|
||||
.benchmade.com TRUE / TRUE 1791760011 ssViewedProducts 4010BK-01
|
||||
.benchmade.com TRUE / TRUE 1791760016 __mmapiwsid 01992148-6176-790f-9637-3c682e38cf66:abbb1dd4308adda60f6fd5c6d973e3d10626ab72
|
||||
.benchmade.com TRUE / TRUE 1788736021 osano_consentmanager_uuid b29340f4-60f9-4647-8eb1-b32488944e24
|
||||
.benchmade.com TRUE / TRUE 1788736021 osano_consentmanager wQMoLX7PZtaJlfz-sjj5K9A9o6kqoGvVi-ZBoD8HiI0yezCa-BNqhG_Vl_ZuQGEyEq3ruGM6-8fmI9Bx5vqNE5gRdx0rDX91eN28lxyyepTJspkSeOMuuUcvLz-tLU_byezjAsVcJm-_2VK9j1tm4mMX0yTRmuO01qYqVar_h9ixOL_aBckoMZWtVeCQZ_4GL3by9HrOBxnBxPcBiOg4awYi_RzpNNtCQaktptOrdK0Sitqh1cXXKWb5M-OU-OCb30yGQcoVz2r0PdEk2O8laKVeeio04id-hbuhK18fv-BlKdTUgUtClp0ft0cD4dnE
|
||||
.benchmade.com TRUE / FALSE 1788757621 _tracking_consent 3pams._USTN_t_f_3D7Z7*ANTre7GLEfvycF*g_{"consent_id":"b29340f4-60f9-4647-8eb1-b32488944e24","consent_timestamp":"2025-09-06T23:07:00.879Z"}
|
||||
.yotpo.com TRUE / TRUE 1788736222 pixel 3c1ab4cd-50fa-40c2-42fe-997c086dedae
|
||||
d-ipv6.mmapiws.com FALSE / TRUE 1791760016 __mmapiwsid 01992148-6176-790f-9637-3c682e38cf66:abbb1dd4308adda60f6fd5c6d973e3d10626ab72
|
||||
.7ce243a1e1a2.cdn4.forter.com TRUE / TRUE 1788736016 forterSId 2436eb89683740e5a1e2611cea77050c_1757200015707
|
||||
d-ipv4.mmapiws.com FALSE / TRUE 1791760016 __mmapiwsid 01992148-6176-790f-9637-3c682e38cf66:abbb1dd4308adda60f6fd5c6d973e3d10626ab72
|
||||
.kys-tech.com TRUE / TRUE 1788978962 __stripe_mid 15f79900-7ee4-4525-84c9-04990e72a685d657ef
|
||||
kys-tech.com FALSE / FALSE 1788978797 info true
|
||||
support.ledger.com FALSE / TRUE 1789655123 CookieConsentPolicy 0:1
|
||||
support.ledger.com FALSE / TRUE 1789655123 LSKey-c$CookieConsentPolicy 0:1
|
||||
.ledger.com TRUE / FALSE 1792679513 _ga GA1.1.677620686.1758119129
|
||||
.ledger.com TRUE / FALSE 1792247129 _scid Rq0GQzyhVgelp7ZQXEj4p4eywsSR_5l2
|
||||
.ledger.com TRUE / FALSE 1792283129 _cs_c 1
|
||||
.ledger.com TRUE / FALSE 1791815180 _tt_enable_cookie 1
|
||||
.ledger.com TRUE / FALSE 1791815180 _ttp 01K5C11W3Y5FE9VY2YJHPS51BG_.tt.1
|
||||
.ledger.com TRUE / FALSE 1792247130 _sctr 1%7C1758085200000
|
||||
.ledger.com TRUE / FALSE 1792283129 _cs_id 04a79f3b-fb89-a1b2-ca66-13a74ef5139b.1758119129.1.1758119180.1758119129.1743519975.1792283129139.1.x
|
||||
.ledger.com TRUE / FALSE 1791815180 ttcsid 1758119129217::4ILjIjLzkvXvFxQSxUaM.1.1758119180327.0
|
||||
.ledger.com TRUE / FALSE 1791815180 ttcsid_CCM80A3C77U9QMO0Q980 1758119129217::DWn4ZxMwXa91S6tK3o9C.1.1758119180716.0
|
||||
.ledger.com TRUE / FALSE 1792247512 _scid_r Ui0GQzyhVgelp7ZQXEj4p4eywsSR_5l2FzAF6Q
|
||||
.ledger.com TRUE / FALSE 1791815512 _uetvid 2929bb5093d211f094dfef3879dafab7
|
||||
.ledger.com TRUE / FALSE 1792681770 _ga_Y38HP2KGC3 GS2.1.s1758121743$o2$g1$t1758121769$j34$l0$h0
|
||||
.waterbear.com TRUE / FALSE 1790346513 AMP_MKTG_e6b575e207 JTdCJTdE
|
||||
.waterbear.com TRUE / FALSE 1793370694 ab.storage.deviceId.48d270e0-354a-41c6-ad46-4879e5b4e0ed g%3A97529535-dcfe-5088-5a99-b222d5a6f6a7%7Ce%3Aundefined%7Cc%3A1758810694823%7Cl%3A1758810694837
|
||||
.waterbear.com TRUE / FALSE 1793370694 ab.storage.userId.48d270e0-354a-41c6-ad46-4879e5b4e0ed g%3ApWAIJMExR2ZkGPyKaCkIMPA9TJI3%7Ce%3Aundefined%7Cc%3A1758810694837%7Cl%3A1758810694838
|
||||
.waterbear.com TRUE / FALSE 1793370716 ab.storage.sessionId.48d270e0-354a-41c6-ad46-4879e5b4e0ed g%3A39d5136d-2c47-c980-7d73-a8d1edcb6b79%7Ce%3A1758812516440%7Cc%3A1758810694837%7Cl%3A1758810716440
|
||||
.waterbear.com TRUE / FALSE 1790347120 AMP_e6b575e207 JTdCJTIyZGV2aWNlSWQlMjIlM0ElMjI5NDE0YWNiMS02NGQ4LTRmZGUtYjk4NC0wMzA1NmQyMjRhMzclMjIlMkMlMjJ1c2VySWQlMjIlM0ElMjJwV0FJSk1FeFIyWmtHUHlLYUNrSU1QQTlUSkkzJTIyJTJDJTIyc2Vzc2lvbklkJTIyJTNBMTc1ODgxMDUxMzg3OSUyQyUyMm9wdE91dCUyMiUzQWZhbHNlJTJDJTIybGFzdEV2ZW50VGltZSUyMiUzQTE3NTg4MTExMjA2NzYlMkMlMjJsYXN0RXZlbnRJZCUyMiUzQTQ0JTJDJTIycGFnZUNvdW50ZXIlMjIlM0EzJTdE
|
||||
.getalby.com TRUE / TRUE 1777649101 cc_cookie {"categories":["necessary","analytics"],"level":["necessary","analytics"],"revision":0,"data":null,"rfc_cookie":false,"consent_date":"2025-07-01T18:52:45.856Z","consent_uuid":"4a542391-0497-4fe9-832d-98ec5c2be76f","last_consent_update":"2025-10-31T15:25:01.672Z"}
|
||||
.getalby.com TRUE / TRUE 1802374856 ph_phc_W6d0RRrgfXiYX0pcFBdQHp4mC8HWgUdKQpDZkJYEAiD_posthog %7B%22%24device_id%22%3A%220197c755-9c24-7cdf-b425-62896d0125c1%22%2C%22distinct_id%22%3A%22nnISDNGBJUIqDV3NGap8%22%2C%22%24sesid%22%3A%5B1770838856866%2C%22019c4e0a-dbc9-7160-a65c-001c2749059e%22%2C1770835860407%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22https%3A%2F%2Fgetalby.com%2Foauth%2Fsessions%2Fnew%3Fclient_id%3DNYvmxLuaWE%26code_challenge%3D2z1VRRvKkLENMiKqy5814MVCv9g6X9UFSIMQXTxFs40%26code_challenge_method%3DS256%26redirect_uri%3Dhttps%253A%252F%252Fgetalby.com%252Fextension%252Fconnect%26scope%3Daccount%253Aread%2Bbalance%253Aread%2Binvoices%253Acreate%2Binvoices%253Aread%2Bpayments%253Asend%2Btransactions%253Aread%22%2C%22u%22%3A%22https%3A%2F%2Fgetalby.com%2Fextension%2Fconnect%3Fcode%3DZTE1MDLLMMMTOTQ5ZC0ZODQ5LWI4OGITZTHJMZJLNJDLNGEY%22%7D%7D
|
||||
.getalby.com TRUE / TRUE 1802371855 cf_clearance HTj7XPrpro_FDlj9EzpTHpJczEspX9S7r9hz9DeMX7w-1770835855-1.2.1.1-DYGWiCTlTQ8QYXzW3_yjuVTzkgs6FWjMM2zaiFFFTA9T_6D8UrAEO1aLmmwWhnoHI4aeKD9GA8KTJgSpoTI3IuHAO_1slPX1BJhKT0cMw7NumWND7WkQj7oFSE6.PuGCuiWRiuT7m2Rq6eqbu3Wu6k0WgfLItvqVoS0CYl1lM8oV0EzHHO6kggSipw5Wbau5rQvUUMzWoQBFgbhll2Lx14jtSmb0H4OznJ9_Wepuyrk
|
||||
.github.com TRUE / TRUE 1795617904 _octo GH1.1.659434916.1764081903
|
||||
.github.com TRUE / TRUE 1795617904 logged_in no
|
||||
.apliiq.com TRUE / FALSE 1799190046 _ga GA1.1.225605822.1764615090
|
||||
.apliiq.com TRUE / FALSE 1799190046 ccid.86838876 347223090.3087116993
|
||||
.apliiq.com TRUE / TRUE 1799190046 apliiq-_zldp hpL8Ey9L33r%2FpBmy3ES%2BLnEa9z5a3Ru0sqYqVOmGsifDZb6QH3ZBTrS1TGiJ%2FcX2T3IUrdIYs4k%3D
|
||||
.apliiq.com TRUE / FALSE 1799190453 _ga_ZL932S8CL9 GS2.1.s1764623129$o4$g1$t1764630453$j59$l0$h0
|
||||
.thrivecap.com TRUE / FALSE 1805844086 _ga GA1.1.1359966912.1764617644
|
||||
.thrivecap.com TRUE / FALSE 1805844086 _ga_CC3XJMND3M GS2.1.s1771284086$o2$g0$t1771284086$j60$l0$h0
|
||||
www.apliiq.com FALSE / FALSE 1799190046 __kla_id eyJjaWQiOiJZMlptTWpFNE4ySXRORFl4T1MwME5Ea3pMVGs1TjJNdE1XTTJPVFU0TmpsaE5EWmwiLCIkZXhjaGFuZ2VfaWQiOiJaYU9CMEwta1FPZjM1M0kxZEpPSVBNM3dzRjZjZVNTbFl2VTQ5aW8tV18wLkxHdkNFWCJ9
|
||||
checkout.apliiq.com FALSE / FALSE 1799189298 __kla_id eyJjaWQiOiJNRFprT1RReVpETXROekppTlMwMFpHTmhMVGcxTW1VdE5tWXpZMlZrWlRRd05EaGoiLCIkZXhjaGFuZ2VfaWQiOiJaYU9CMEwta1FPZjM1M0kxZEpPSVBNM3dzRjZjZVNTbFl2VTQ5aW8tV18wLkxHdkNFWCJ9
|
||||
.checkout.apliiq.com TRUE / TRUE 1799189183 apliiq-_zldp hpL8Ey9L33r%2FpBmy3ES%2BLnEa9z5a3Ru0sqYqVOmGsifDZb6QH3ZBTrS1TGiJ%2FcX2T3IUrdIYs4k%3D
|
||||
.gfore.com TRUE / FALSE 1796108616 visid_incap_2081288 fR3D7pzZRNClUUXvZ0djUlMPLmkAAAAAQUIPAAAAAAAR7nhfh+ALBI09CWSIi1xz
|
||||
.gfore.com TRUE / FALSE 1780394277 _conv_v vi%3A1*sc%3A1*cs%3A1764626267*fs%3A1764626267*pv%3A1*exp%3A%7B100493634.%7Bv.1004224736-g.%7B%7D%7D%7D
|
||||
.gfore.com TRUE / FALSE 1780178277 _conv_r s%3Awww.google.com*m%3Aorganic*t%3A*c%3A
|
||||
.gfore.com TRUE / TRUE 1796162268 BVBRANDID 2713ee0a-f16b-4724-ae7f-64dd6f7d9358
|
||||
.gfore.com TRUE / FALSE 1796162268 crl8.fpcuid 9ef62d87-b733-4303-9d76-cc57c9954c3a
|
||||
.gfore.com TRUE / FALSE 1798581468 TCPID 12512115574812185174123
|
||||
.gfore.com TRUE / FALSE 1798322268 TC_PRIVACY_CPRA 0%40005%7C1%7C6985%401%2C2%403%2C4%401764626268380%40
|
||||
.gfore.com TRUE / FALSE 1798322268 TC_PRIVACY_CPRA_CENTER 1%2C2
|
||||
.gfore.com TRUE / FALSE 1798754268 __cq_uuid abc0mIAQzkjEcz7G7jKiIAQmA6
|
||||
.gfore.com TRUE / FALSE 1799186269 _ga_XXXXXXX1 GS2.1.s1764626268$o1$g0$t1764626268$j60$l0$h0
|
||||
.gfore.com TRUE / FALSE 1799186269 _ga GA1.1.2041936879.1764626268
|
||||
.gfore.com TRUE / FALSE 1799186269 _blkp_xps %7B%22HJSHP%22%3A13%7D
|
||||
.gfore.com TRUE / FALSE 1799186269 tatari-session-cookie 4d93019f-1130-10d7-88d7-ba789134d1f2
|
||||
.gfore.com TRUE / TRUE 1798322269 __attentive_id f80a08145ae84bb4a15e3522ddf6ec89
|
||||
.gfore.com TRUE / TRUE 1798322269 _attn_ eyJ1Ijoie1wiY29cIjoxNzY0NjI2MjY5MTAxLFwidW9cIjoxNzY0NjI2MjY5MTAxLFwibWFcIjoyMTkwMCxcImluXCI6ZmFsc2UsXCJ2YWxcIjpcImY4MGEwODE0NWFlODRiYjRhMTVlMzUyMmRkZjZlYzg5XCJ9In0=
|
||||
.gfore.com TRUE / TRUE 1798322269 __attentive_cco 1764626269102
|
||||
.gfore.com TRUE / FALSE 1798790269 _cs_c 0
|
||||
.gfore.com TRUE / FALSE 1798790269 _cs_id 67f94baa-0c07-aa0a-8730-2b163746ee77.1764626269.1.1764626269.1764626269.1732464474.1798790269114.1.x
|
||||
.gfore.com TRUE / FALSE 1798322269 _uetvid c6d49190cf0011f0aeea9b5244ce38a2
|
||||
.gfore.com TRUE / FALSE 1799186269 forterToken e336e2a1c101466cab21e3b0cd875de2_1764626267339__UDF43-m4_15ck_
|
||||
.gfore.com TRUE / FALSE 1796162270 _ju_dc c76c9bf6-cf00-11f0-b023-2f66809d83c9
|
||||
.gfore.com TRUE / FALSE 1799186271 _lc2_fpi 8dce54196be4--01kbdyr369gqe5hbzn8fmg8sjx
|
||||
.gfore.com TRUE / FALSE 1799186272 _li_ss CgA
|
||||
.gfore.com TRUE / FALSE 1799186586 _ga_B0REW2WZF3 GS2.1.s1764626268$o1$g1$t1764626585$j60$l0$h411637605
|
||||
www.gfore.com FALSE / TRUE 1780178266 dwanonymous_9075bc7ed73102844fcce4f0052fc396 abc0mIAQzkjEcz7G7jKiIAQmA6
|
||||
www.gfore.com FALSE / FALSE 1799186269 __kla_id eyJjaWQiOiJNRGRsWm1JNFpUVXRObUkzWmkwME9HUmhMV0ppT1dNdFl6RTVORGc0WXpReE5EaGoifQ==
|
||||
www.gfore.com FALSE / FALSE 1799186269 tatari-cookie-test 7751488
|
||||
www.gfore.com FALSE / FALSE 1796162271 mmuid 8bc762a20cf84eb3
|
||||
.cquotient.com TRUE / TRUE 1798754268 uuid abc0mIAQzkjEcz7G7jKiIAQmA6
|
||||
.pippio.com TRUE / TRUE 1796162270 did 2lV2IoCTOVt2NS-_
|
||||
.pippio.com TRUE / TRUE 1796162270 didts 1764626270
|
||||
.stats.paypal.com TRUE / FALSE 1799189168 c 98d9b886327596d2998e
|
||||
www.paypal.com FALSE / FALSE 1796165182 _dd_s aid=5e3e2398-f9b0-450b-b96d-81e19d3ab6eb&rum=1&id=9519a9a5-c971-467f-9f02-e159e9c6b04c&created=1764628902830&expire=1764630082507
|
||||
.zaprite.com TRUE / FALSE 1799190233 _ga GA1.1.1488010542.1764630150
|
||||
.zaprite.com TRUE / FALSE 1799190191 _ga_XFZVJST60H GS2.1.s1764630150$o1$g1$t1764630190$j20$l0$h0
|
||||
.zaprite.com TRUE / FALSE 1799190233 _ga_DKN4TFVCXF GS2.1.s1764630191$o1$g1$t1764630233$j18$l0$h0
|
||||
.zaprite.com TRUE / FALSE 1787960234 intercom-id-vvv6kprm 53fb38b9-0790-4323-ad0d-bf81666b8e17
|
||||
.zaprite.com TRUE / FALSE 1787960234 intercom-device-id-vvv6kprm 28349a77-ec40-4fa5-8b4d-40552ffac9bb
|
||||
.zaprite.com TRUE / FALSE 1799190340 _ga_7GLS7Z6F3N GS2.1.s1764630233$o1$g1$t1764630339$j60$l0$h0
|
||||
skims.com FALSE / TRUE 1797188683 _skid 65794e07-1d7d-4046-82d7-97b491f2207a
|
||||
skims.com FALSE / TRUE 1797188683 _visitingStatus visited
|
||||
skims.com FALSE / TRUE 1797620763 __rtbh.lid %7B%22eventType%22%3A%22lid%22%2C%22id%22%3A%22YlhgkQKyMucYj6OgV707%22%2C%22expiryDate%22%3A%222026-12-18T19%3A06%3A03.356Z%22%7D
|
||||
skims.com FALSE / FALSE 1800644764 __kla_id eyJjaWQiOiJNbVF4WW1JeFpXRXRORGcxTkMwME9ESmhMV0ppTkRFdFpERmhaamRrWldRNE56Z3kifQ==
|
||||
skims.com FALSE / TRUE 1797620837 __rtbh.uid %7B%22eventType%22%3A%22uid%22%2C%22id%22%3A%2265794e07-1d7d-4046-82d7-97b491f2207a%22%2C%22expiryDate%22%3A%222026-12-18T19%3A07%3A17.905Z%22%7D
|
||||
.skims.com TRUE / FALSE 1800644684 GLBE_SESS_ID %7B%22sid%22%3A%22467132306.141432646.1155%22%2C%22expiry%22%3A%222025-12-18T19%3A34%3A43.788Z%22%7D
|
||||
.skims.com TRUE / FALSE 1797620762 _pin_unauth dWlkPVptSTNNak5tWkRrdE1tUXpNQzAwWmpRMExUbGpOV1l0Tm1Zd1lXTTJOVGhqTW1ObQ
|
||||
.skims.com TRUE / FALSE 1799780762 _tt_enable_cookie 1
|
||||
.skims.com TRUE / FALSE 1799780762 _ttp 01KCSDKA6XDMKRKZPT7DCE4AP2_.tt.1
|
||||
.skims.com TRUE / FALSE 1797188837 _shopify_y 32d9af33-1480-4758-D61F-71903CC651A6
|
||||
.skims.com TRUE / FALSE 1800644763 _ga GA1.1.504031878.1766084685
|
||||
.skims.com TRUE / FALSE 1800644685 _lc2_fpi 21287e9a14d4--01kcsdkavhydvmffvv0jxfzemq
|
||||
.skims.com TRUE / TRUE 1799780764 __attentive_id 47bbcb9b962e4edca1e9cbef53e28d00
|
||||
.skims.com TRUE / TRUE 1799780763 _attn_ eyJ1Ijoie1wiY29cIjoxNzY2MDg0Njg0Njc3LFwidW9cIjoxNzY2MDg0Njg0Njc3LFwibWFcIjoyMTkwMCxcImluXCI6ZmFsc2UsXCJ2YWxcIjpcIjQ3YmJjYjliOTYyZTRlZGNhMWU5Y2JlZjUzZTI4ZDAwXCJ9In0=
|
||||
.skims.com TRUE / TRUE 1799780684 __attentive_cco 1766084684678
|
||||
.skims.com TRUE / TRUE 1797620684 __ps_r _
|
||||
.skims.com TRUE / TRUE 1797620684 __ps_lu https://skims.com/collections/nikeskims?direction=next&cursor=eyJsYXN0X3ZhbHVlIjoiNDciLCJsYXN0X2lkIjoxMDI0Njg2MDI0MzI5Nywib2Zmc2V0Ijo0N30%3D
|
||||
.skims.com TRUE / TRUE 1797620684 __ps_did pscrb_226743b1-9d44-4bb8-f968-04a31e8f8041
|
||||
.skims.com TRUE / TRUE 1797620684 __ps_fva 1766084684717
|
||||
.skims.com TRUE / TRUE 1800644685 IR_PI 6a48fb22-dc44-11f0-870a-6584898419f4%7C1766084684614
|
||||
.skims.com TRUE / FALSE 1797620684 _axwrt 8c9ab40d-c69d-4ee6-9183-e996d8a1c7b8
|
||||
.skims.com TRUE / FALSE 1800299084 _scid JRoE-ZvIBUJLSPCc1lIQKUMvwHza3_Nj
|
||||
.skims.com TRUE / FALSE 1799953485 __qca P1-9906de41-ac66-4d3d-9d15-0f1f3e39e286
|
||||
.skims.com TRUE / TRUE 1797620766 QuantumMetricUserID 98414e535c76313591f9ee355cff76c4
|
||||
.skims.com TRUE / FALSE 1800299085 _sctr 1%7C1766037600000
|
||||
.skims.com TRUE / FALSE 1800644838 __ta_device ubGuBKNdUrjeaI0JaQhs4JFAcl4tQMLC
|
||||
.skims.com TRUE / TRUE 1797620760 _dy_soct 1766084760!1159934.-77'1159935.0'1272376.0'2016990.0!adg54ijwhx2tu6ef4um4hp3eo8uhne4p~1159939.-77'1324063.-77'1327720.0
|
||||
.skims.com TRUE / FALSE 1797620760 OptanonConsent isGpcEnabled=0&datestamp=Thu+Dec+18+2025+13%3A06%3A00+GMT-0600+(Central+Standard+Time)&version=202306.1.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=afbd17d7-6dcd-40fa-98d8-cdc9ff46f400&interactionCount=1&landingPath=NotLandingPage&groups=BG34%3A1%2CC0001%3A1%2CC0002%3A1%2CC0003%3A1%2CC0004%3A1&geolocation=US%3BTN&AwaitingReconsent=false
|
||||
.skims.com TRUE / FALSE 1797620760 OptanonAlertBoxClosed 2025-12-18T19:06:00.956Z
|
||||
.skims.com TRUE / FALSE 1797620761 _tracking_consent 3AMPS._USTN_f_t_0zEbzYtoSAGJag49cJEAlg
|
||||
.skims.com TRUE / FALSE 1800299163 _scid_r PpoE-ZvIBUJLSPCc1lIQKUMvwHza3_NjkUotaA
|
||||
.skims.com TRUE / FALSE 1799780763 _uetvid 6a477db0dc4411f0b033537fd8e9476f
|
||||
.skims.com TRUE / FALSE 1800248763 cto_bundle lxezUl9Ya05KT0lxalRzMlpmQTZ1WnNGcGVTa2FaVEtiTWIlMkJKY29ZSDRVM0Z1VGlwU3pqMWpLRm9OdUs5MWZLJTJCd1ZxbiUyQnByYVJXWE16QlhOS0FlVSUyRkI3aUwlMkY0a1pQTjN3ZkJaSDR6TjZGTlNWWEl6NnRVbmFzeWc2aHhQeVREcUVNYmZRM2tiT0pwayUyQjAlMkJNUCUyQkYwUFBDMSUyRnNQbmglMkZUUElseHdZbTZ6NVFzenF1bHNJckVuTGtLNyUyRmgwbzFwclEzb3Y0
|
||||
.skims.com TRUE / FALSE 1800644765 forterToken 0dc56201e2d447c483dafc18afc4d80f_1766084760076__UDF43-m4_23ck_
|
||||
.skims.com TRUE / TRUE 1797620837 _Elevar-apex [1%2C%2265794e07-1d7d-4046-82d7-97b491f2207a%22%2C%221766084684%22%2C%221%22%2C%221766084837%22%2C{}%2C[]%2C%22{%5C%22_ttp%5C%22:%5C%2201KCSDKA6XDMKRKZPT7DCE4AP2_.tt.1%5C%22%2C%5C%22_fbp%5C%22:%5C%22fb.1.1766084684456.3724806368%5C%22%2C%5C%22_uetsid%5C%22:%5C%226a4786e0dc4411f0be072b25ff65504f%5C%22%2C%5C%22_uetvid%5C%22:%5C%226a477db0dc4411f0b033537fd8e9476f%5C%22%2C%5C%22_ga%5C%22:%5C%22GA1.1.504031878.1766084685%5C%22%2C%5C%22_scid%5C%22:%5C%22JRoE-ZvIBUJLSPCc1lIQKUMvwHza3_Nj%5C%22%2C%5C%22_ga_FB40M4FWKG%5C%22:%5C%22GS2.1.s1766084684$o1$g1$t0$j60$l0$h0%5C%22}%22%2C0]
|
||||
.skims.com TRUE / TRUE 1800644838 _sp_id.5e0d cffe6173-3fe8-42c0-ba5a-5752434cd290.1766084685.1.1766084838..343b2361-d02d-43ff-aef6-a93963ca8f87..69e731b2-03d7-4e90-be5a-612485fa927c.1766084684861.18
|
||||
.skims.com TRUE / FALSE 1799780852 ttcsid 1766084683999::SeCLjuB76f1lL4FbZ7aD.1.1766084852083.0
|
||||
.skims.com TRUE / FALSE 1799780852 ttcsid_C0VSMI3M56Q7UP188TTG 1766084683999::x8lq-MdBmPA7eS2m0G8k.1.1766084852083.1
|
||||
.skims.com TRUE / FALSE 1797620858 ax_visitor %7B%22firstVisitTs%22%3A1766084684723%2C%22lastVisitTs%22%3Anull%2C%22currentVisitStartTs%22%3A1766084684723%2C%22ts%22%3A1766084858302%2C%22visitCount%22%3A1%7D
|
||||
.skims.com TRUE / FALSE 1800644858 _ga_FB40M4FWKG GS2.1.s1766084684$o1$g1$t1766084858$j13$l0$h0
|
||||
.wsktbf.net TRUE / TRUE 1797620685 brwsr 6a48fb22-dc44-11f0-870a-6584898419f4
|
||||
skims.wsktbf.net FALSE / TRUE 1781636685 irld L0DYwUSVnS1txSuPWHEVUBzXyUHPUSrSv2T1XXKQ1CYx9uScp
|
||||
.applovin.com TRUE / TRUE 1797620764 axcrt AL.1.749430528.1766084684889.3
|
||||
.snapchat.com TRUE / TRUE 1799780686 sc_at v2|H4sIAAAAAAAAAE3GwRGAMAgEwIqY4RAPsJuYkCpSvF/3tT13LqKENi7xek1GISQStYC2nvvA9UGQms68z6/6AQMbeYBAAAAA
|
||||
.360yield.com TRUE / TRUE 1775862466 tuuid 7fafe40b-12f1-414e-b944-2666315f73d5
|
||||
.360yield.com TRUE / TRUE 1775862466 tuuid_lu 1768086465
|
||||
.360yield.com TRUE / TRUE 1775862471 umeh !38,0,1828292838,-1!313,0,1830294470,-1
|
||||
.360yield.com TRUE / TRUE 1775862471 um !38,BMXavnbDSbrtd4.oP9GgaGHhGMIsdH1-0lojSjX0SUYXrIy507xIiBaWovN6Gzrz7PILKsTxjEyEIbK8RGgFG9lKZIw,1773860838!313,VFhMj4Rogp5bPH3bortlS155AbhA1mgZO86CZ1CUUsJ0Xfzu4KyqVsRHFR4jb-gbyldYYBTzwDrUjjgSqyqqA468msGKMkHPsMMcw4etS9OxrT1l,1775862470
|
||||
.3lift.com TRUE / TRUE 1775862514 tluid 1095917909795168967170
|
||||
.3lift.com TRUE / TRUE 1775862514 receive-cookie-deprecation 1
|
||||
.3lift.com TRUE / TRUE 1775862479 tluidp 1095917909795168967170
|
||||
.toast.com TRUE / TRUE 1781636741 BID RSSB37CZ5JRWID3174XWCDKWI
|
||||
.toast.com TRUE / TRUE 1781636741 txpub_1570163526 d2OEmVpH39gWAzy-La7n8Vs1CcRnjHNo9i5CbT-KnV8_:_EXP_:_1781636740_:_EXP_:_1766084740
|
||||
.toast.com TRUE / TRUE 1781636741 txsync 1766084740
|
||||
.nhnace.com TRUE / TRUE 1781636742 BID RSSB37CZ5JRWID3174XWCDKWI
|
||||
.nhnace.com TRUE / TRUE 1781636742 txpub_1570163526 d2OEmVpH39gWAzy-La7n8Vs1CcRnjHNo9i5CbT-KnV8_:_EXP_:_1781636741_:_EXP_:_1766084741
|
||||
.nhnace.com TRUE / TRUE 1781636742 txsync 1766084741
|
||||
.bidence.net TRUE / TRUE 1781669204 177_dsp_uid d2OEmVpH39gWAzy-La7n8Vs1CcRnjHNo9i5CbT-KnV8
|
||||
.bidence.net TRUE / TRUE 1781669204 duid_update_time 1766084803
|
||||
.bidence.net TRUE / TRUE 1781669204 114_ssp_update_time 1766084803
|
||||
.fwmrm.net TRUE / TRUE 1783638470 _uid umwbe31_7585846274144387383
|
||||
.ct.pinterest.com TRUE / TRUE 1797620838 _pinterest_ct_ua TWc9PSZWOW5BTVRpai94Y2ZzVm1seFNIOTROcXhJRlg1VUlYbUh2bDdERE8yWGhKVVJQSTFuOGt4YXhQTS9iamdSakp4SDJtbzhudlNnamZvdE01YVRxa2Q2VTkxdnlOb0J5YUZ5RGJqMEVZbVNqOD0mUEI4L2tkbFJySmhRKzhQb01FbU5JTVd1cUNvPQ==
|
||||
.vour.io TRUE / TRUE 1797620838 624_jwt eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhaWQiOiI5ZGYzMTczNC00ZGU5LTQxZmEtOTE4Ny0xMzRkNzM1YTU2NmUiLCJpYXQiOjE3NjYwODQ4Mzh9.MbIIoNSNCU_wsXuJOi4ja0I7YU83U5d3bu7IF4_ejKBJHxyMfxg6Hrly89pXFYMvHidqEGIzm9flveSs-Gsgqazc4-3XCP0iT7IkmRcr0iujb3gv_PxYIoBcO7r3UPxniRSAB3cxakZaPArmSWXWWmPj2xpGb7beTPjC6abp827UG0ezAMruCrRJCYpaFBR_OMj9T3QIzV6syrVwbW1kshiZikQU8o2lEUt32tOv99cmPsMqfxuXpDgVUzp9ZMlSXSaor5_o8-M61B_MFXptlEtAb4BvX_DM8GJ77QJQl7Cghv0EdZMhAsPTpL7rk7MFfvuwckLXjmaTuADhIHow1g
|
||||
.bestbuy.com TRUE / FALSE 1797709170 vt 6f690ae0-dd12-11f0-ad0a-0ee7b207dce3
|
||||
.bestbuy.com TRUE / FALSE 1776541172 pst2 170|N
|
||||
.bestbuy.com TRUE / TRUE 1799869172 __gads ID=429e68df663c9775:T=1766173172:RT=1766173172:S=ALNI_MZxhbQ31SYi0pxCdtetDZIMIskvdg
|
||||
.bestbuy.com TRUE / TRUE 1799869172 __gpi UID=0000131de02f3466:T=1766173172:RT=1766173172:S=ALNI_MbY9XCpzTvLqqUz0Rh78RjXf_ofgQ
|
||||
.bestbuy.com TRUE / TRUE 1781725172 __eoi ID=ca0d26dfc81cc6e4:T=1766173172:RT=1766173172:S=AA-AfjZtPe0_KiUjvlJ2NBiOFOBD
|
||||
.bestbuy.com TRUE / TRUE 1797709172 connectId {"connectId":"h41BbgQlSIHyJId5O-APjmQCXBg7b6ibxGpJLV7EEg81n8_XB96ECUyAVHwglTQesGfGtFseQZoaAKJHFHAVUw","puid":"05d8092bdb6760329fb8a13189c0cec789c100d61d0b4412e73274ed53edd6fc","ttl":86400000,"lastUsed":1766173172442,"lastSynced":1766173172442}
|
||||
.bestbuy.com TRUE / FALSE 1800733182 s_ecid MCMID%7C58080136048519668114536865538030263176
|
||||
.bestbuy.com TRUE / FALSE 1800733182 AMCV_F6301253512D2BDB0A490D45%40AdobeOrg 1585540135%7CMCMID%7C58080136048519668114536865538030263176%7CMCAAMLH-1766777971%7C7%7CMCAAMB-1766777971%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%7CMCOPTOUT-1766180382s%7CNONE%7CMCAID%7CNONE%7CvVersion%7C4.4.0
|
||||
.bestbuy.com TRUE / FALSE 1800337186 _cs_c 1
|
||||
.bestbuy.com TRUE / TRUE 1797709196 _abck 98CE9281062EB29755F518F4E2632889~0~YAAQEX0vF7RqhzabAQAA9z4gOA8ujjyFR4zYs1rTxYLHEURlVdJ4OtbhDy2zsBP4b4YveBwzZEbAo/jJGNgPComzkF8zGClPAFi44WsKxhS0LcWx6mvKZwMZtasW5nI+Z4FLt7A89ko3d2NfGaS4fasItIDYUP54kWyyLcB+cwDYnTmI+1Qwr/vWiC880Y/fhiAI4vgA6Fqn9xNfnZFz4Ivj7G3UImaIw+Q2oS0OIPIoPWr8LVxBYVf0nJ/SOUj76gPaJNDc7Rf78NsjZSwr8lYK/aQV6nV2iRDQjUjasDmLCnbTGrfAQdfRE+crv41URBptfgxqnlbloME7Vkuf4W/ylVjgBGytkzzx0wu0jiHAcV3cPpjXBLnN2kAcHYSn4UoXJPgeXYz4ycnbntI9HQ6k5Mw9hrIAVXTt7vFN5ZyrGYwLOAWXAktezAqRct+YLUZV2FS3HxhFlmL2MGvsXJ3GNz9geF1JXYeilGM8Tay1FYQ2wfwI6oc+a9nDbH9DjnKE7HqLr3XJ5kxMU47KiXjJu+hyX1TedaZLMg5Aot3zFf/nvz9QwF71Z268ZX9FlTJmm2tAYC0zFlU8Dz70IacyvsiFcpHSsGwrt+16yk/hNkZyamYM6c1SyxOoju+lNvUTuAyuW4uyLvUQ5WQWE5C93ccebJnn~-1~-1~1766176771~AAQAAAAE%2f%2f%2f%2f%2f8oOA3tv34D2V7ONQZtmPYLejQtQVkGWs%2fvwofeeythQgyIiBizjnFUkvIb9LGyVvOYCw3xNHy+m86G3W50LV006WFXInvjS6rNE~-1
|
||||
.bestbuy.com TRUE / FALSE 1800337196 cto_bundle xqwVuV94ejhqbTA4bHB4b0JiNVVxcFclMkZPRUdwWUhuUTFUbGx6ZE9UWXZmVTczaDNSNSUyQkJ0TW90T3glMkJQODgycmpFR3hTN0REZWVJSUV0OHRxNUJxNXp4RW5xclNOdGQ2cXlMQTk1NlpVSFhybGFHYU1nbFNVYUx5MUdlUWZUcjA0bmZmbm1jbFZNOXFPaXE3NkxMQndoZiUyQjd6S2w0S1dBNTQyNEtjMEJxdGhFZTZybTl5VWZiUjAySndURDFjME1SYTh2VQ
|
||||
.bestbuy.com TRUE / FALSE 1797709214 isGridViewEnabled true
|
||||
.bestbuy.com TRUE / FALSE 1799869219 __gsas ID=78bad4b99391fe9a:T=1766173219:RT=1766173219:S=ALNI_MZ7PtsAhyKgA-RaJ1wnpzOGAacHDQ
|
||||
.bestbuy.com TRUE / FALSE 1800337186 _cs_id 178c060b-ebba-a692-ebdd-0fc62bd54d08.1766173186.1.1766173232.1766173186.1645469968.1800337186882.1
|
||||
.bestbuy.com TRUE / FALSE 1797709247 locDestZip 37024
|
||||
.thingiverse.com TRUE / TRUE 1801782464 __gads ID=c274a2d1d73e5390:T=1768086464:RT=1768086464:S=ALNI_Mb0CVH9vFv-SqEXC4e1YO_sN8flTw
|
||||
.thingiverse.com TRUE / TRUE 1801782464 __gpi UID=00001324f4cc2db5:T=1768086464:RT=1768086464:S=ALNI_MaewbhT_k00lySbZa5mbAYBf7rQdw
|
||||
.thingiverse.com TRUE / TRUE 1783638464 __eoi ID=6378ed39ac9fb0ea:T=1768086464:RT=1768086464:S=AA-Afja98XhAT6jufaqPVnOucN-S
|
||||
.thingiverse.com TRUE / FALSE 1791414465 _cc_id 3cf9e41188988b992aee1510314411e1
|
||||
.thingiverse.com TRUE / FALSE 1801760863 cto_bundle abRd819vSkMzOGd0M2dGSk5FSnpOd25ydFd4dDhpNEMlMkJXQjVBNjF6bXVpaURpYTBJbEFvWEU1V3NWUjhOMiUyRnZoZ1ZxY0QwJTJCc1ZBRTV4Vk1ZMkFERmslMkZXSnhSTVAzQXlmMUxwWEp0S3JYRmtjc1U2NnR0M1Q5RlB4N2VZN0VrNTk5YzB2Nm9TWld4RWNJRE9kNGFJaHN6eFlheDk1Ynd0QXdsN0xWckxYMDhMamRKSlRIS1hHM2pxMkhLcUJic0ZIUHFNYg
|
||||
.thingiverse.com TRUE / FALSE 1801760863 cto_bidid mnWdDV9nbG84Y0Z1Zm1lRU9vMEVnJTJGdWQyODhXQjM0WTZlRSUyRkRaOUI2dFdKZWVac1hDcnJmZiUyRjA5NzNDcTFXUEdXekFiMXRwTm9IYmJiZDJ6ZHJvUnNjJTJCUWE0VldzdFhtc041MlBCdU5mWjNNYVZXUm0lMkZiWTFReXFWeTJhektHUCUyQm16UmhMJTJGQ29ZeTVTR1g0ZSUyRnh0dldib0x3JTNEJTNE
|
||||
.thingiverse.com TRUE / TRUE 1799622465 cf_clearance hwUXmBceIFvRDfbB2BtWlQCpzcjHbmiSqo5cz6aGdEc-1768086465-1.2.1.1-VX.Q4T4aESaY6xi9IRJfTIQDfpvdaoxXMckW7vY8vmQkx7u4vX3Bdu5s_u0xmy89GTnveSCQ0SJlfHk7pQu3UaXVaPtbCRViQF9Oyu4u64vlE1o1XegeKxhhNX95YA7bSOfsRrr1UrxF1_8QTgKwoEDJhXOchZj2r_3TfpfHGgz02di9c5oXG_3SqG93ctZEyEEHU4SucDaTIPUEElZ1pZ81RwmbGGX2uHkTFWremag
|
||||
.ipredictive.com TRUE / TRUE 1799622470 cu 066d8e19-5c26-450d-a649-863f2909f959|1768086465860
|
||||
.csync.loopme.me TRUE / TRUE 1775862478 viewer_token 2ca038bf-483c-4eaa-b684-a7905f94dc41
|
||||
.33across.com TRUE / TRUE 1799622479 33x_ps u%3D212328208636113%3As1%3D1698785496328%3Ats%3D1768086466187
|
||||
.opera.com TRUE / TRUE 1799622478 OAU OPUb598e447ff4b444484a3e5b793c7de50
|
||||
.xplosion.de TRUE / TRUE 1799622467 pid BSRCEif3WD_CWDa0WSRAEibkWSRsWD_8WiRkWi_ABifABfrr
|
||||
.xplosion.de TRUE / TRUE 1799622467 pid_short 52I3odHeaUJ3xI5D_DbFH5_8__rr
|
||||
.xplosion.de TRUE / TRUE 1799622467 pid_signature wSulwSjDBSU0wDjdwSBsWDU-wCHbWDwZWq7kBStIEiujwqUAEiU0Hfrr
|
||||
.xplosion.de TRUE / TRUE 1799622467 ep aWLbwkDbaJugE4bcG2i-
|
||||
.trustedstack.com TRUE / TRUE 1802387267 visitor-id 4110880664639125000V10
|
||||
.adfarm1.adition.com TRUE / TRUE 1775862469 UserID1 7593873548017072489
|
||||
.bttrack.com TRUE / TRUE 1775862468 GLOBALID 2uKlc8-sIBd984cSkD72DtzNhbXQZOzWrDrHRMWhaK7Tgu7vGY-DLeTd831jGxj6xBOn4fvgsrMC4Q2
|
||||
.simpli.fi TRUE / TRUE 1799708868 suid F807DADE2E214302BF3C6F3D58A4CEC8
|
||||
sync.srv.stackadapt.com FALSE / TRUE 1799622468 sa-user-id s%3A0-4629e297-6daa-5181-62e1-392785235d6f.PXNulmzJegZOvvWPXXg3lwleRwh%2F0%2B5MSVe1ySIMGEM
|
||||
sync.srv.stackadapt.com FALSE / TRUE 1799622468 sa-user-id-v2 s%3ARinil22qUYFi4TknhSNdb2vCVQw.ezE7srbmqWgoMYYglaxkS%2BF8s6cNlNz0M9lOXWpG0ek
|
||||
sync.srv.stackadapt.com FALSE / TRUE 1799622468 sa-user-id-v3 s%3AAQAKIOnhejbOhrV9-RM6AiFzDEwt3Ih8NIHekYWJsIGp7nzbEAMYAyDEt4vLBjABOgQTDjy1QgR2YepB.2F4w74GAZt5vjDhOMoMUFticPP20T51xHtlrhiwpK%2Bo
|
||||
.srv.stackadapt.com TRUE / TRUE 1799622468 sa-user-id s%3A0-4629e297-6daa-5181-62e1-392785235d6f.PXNulmzJegZOvvWPXXg3lwleRwh%2F0%2B5MSVe1ySIMGEM
|
||||
.srv.stackadapt.com TRUE / TRUE 1799622468 sa-user-id-v2 s%3ARinil22qUYFi4TknhSNdb2vCVQw.ezE7srbmqWgoMYYglaxkS%2BF8s6cNlNz0M9lOXWpG0ek
|
||||
.srv.stackadapt.com TRUE / TRUE 1799622468 sa-user-id-v3 s%3AAQAKIOnhejbOhrV9-RM6AiFzDEwt3Ih8NIHekYWJsIGp7nzbEAMYAyDEt4vLBjABOgQTDjy1QgR2YepB.2F4w74GAZt5vjDhOMoMUFticPP20T51xHtlrhiwpK%2Bo
|
||||
www.thingiverse.com FALSE / TRUE 1799622468 CookieConsent {stamp:%27dcCI10BHlJQetn3alh3J9z8IPiGNGQgScRgD0Fmt+ZeQiYr0g1z1WQ==%27%2Cnecessary:true%2Cpreferences:false%2Cstatistics:false%2Cmarketing:false%2Cmethod:%27explicit%27%2Cver:3%2Cutc:1768086468362%2Cregion:%27us-47%27}
|
||||
.presage.io TRUE / TRUE 1783897669 presage-ssp %7B%22uuid%22%3A%2239a603b9-8fc8-42ed-b4f9-05588b5ca524%22%7D
|
||||
.use3-sync.a-mo.net TRUE / TRUE 1799622469 sd_amuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.use3-sync.a-mo.net TRUE / TRUE 1799622469 psd_amuid2 6694de3f-a4e4-4153-be90-38070f322c76
|
||||
.dxtech.ai TRUE / TRUE 1783638469 mtuid 2f39f687-b1fe-4539-85b6-f60b92005b47
|
||||
.media6degrees.com TRUE / TRUE 1783638469 clid 2smn2ow011718bshr4m678srm15k500i0a010201101
|
||||
.media6degrees.com TRUE / TRUE 1783638469 sglst 453a3mcu03o9yj21fo95q21f1liw0q607mu018dl30q6
|
||||
.media6degrees.com TRUE / TRUE 1783638469 rdrlst 5515401j084uk20q64ujk0q64uim0q64sz80q64hkx0q649pl0q62dc00q629zg0q6
|
||||
.media6degrees.com TRUE / TRUE 1783638469 acs 015020i0j0k0o1smn2owxzt1m15k5xzt1m15k5xzt1m15k5xzt1m15k5
|
||||
.resetdigital.co TRUE / TRUE 1775862469 ckbk 000011CF9CE959F2
|
||||
.advolve.io TRUE / TRUE 1799622469 x 6962dbc575e323aa0d79326e
|
||||
.driftpixel.live TRUE / TRUE 1799622469 xedpxl 12261041.8bc2613b-cb1c-4e2c-9de0-564b760c7596
|
||||
cookies.nextmillmedia.com FALSE / TRUE 1799622478 NMUID c268b853-3d21-4300-bbd4-17f459389def
|
||||
.quantserve.com TRUE / TRUE 1775862470 sp CgkI6KsGEgMQghEKCQiCrQMSAxCCEQoICNllEgMQghEKCQjRpgISAxCCEQoICIkNEgMQmREKCAieDRIDEIIRCgcICxIDEIIRCggIknESAxCZEQoJCLmKAxIDEJkRCgkIhf8CEgMQghE=
|
||||
.pmbmonetize.live TRUE / TRUE 1799622470 xeadiu 12090783.fd98a23a-b3d0-487c-8fc9-8f1b434f671e
|
||||
.rbstsystems.live TRUE / TRUE 1799622475 xeroid 11690718.a267af1d-fded-4805-82f1-a40eb66eb5a4
|
||||
.nextmillmedia.com TRUE / TRUE 1799536070 adkernel eyJVSUQiOiJBNjc4MTQ0ODEzNTM2NDc0NjgxMCIsIkV4cGlyZXMiOiIyMDI3LTAxLTA5VDIzOjA3OjQ5Ljk5MzczMjk0WiJ9
|
||||
.nextmillmedia.com TRUE / TRUE 1799536070 rubicon eyJVSUQiOiJNNkNGNFRHOC1XLUo3MFMiLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1MC40MDk1MjQ5NDVaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 adnxs eyJVSUQiOiIxNDQ2NjY0NjMzMDYyNDU1NzM4IiwiRXhwaXJlcyI6IjIwMjctMDEtMDlUMjM6MDc6NTUuMzMwNDU3NVoifQ==
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 openx eyJVSUQiOiJkNjk4MWFlNy00ZWE1LTQ5NjUtODVjNi0zNDUzYTdjMDE0NTYiLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1NS4zNDAxNjk2OTVaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 pubmatic eyJVSUQiOiI3RUE1NURBRC01RUQxLTQyREQtQUZGNy05NkIwMTg3RTJGRTgiLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1NS4zNDYxNjA1MzlaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 yieldmo eyJVSUQiOiIzZUhQdkhIYm1QSHhTdE1vSVhPUiIsIkV4cGlyZXMiOiIyMDI3LTAxLTA5VDIzOjA3OjU1LjM1NzU5ODM1NloifQ==
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 sovrn eyJVSUQiOiJIbEhDVVJaSG1uR1lfaHR3UnkycWRTN1giLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1NS4zODQyMDE3MDlaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 verve1 eyJVSUQiOiJiYzY3MTE5MTY4IiwiRXhwaXJlcyI6IjIwMjctMDEtMDlUMjM6MDc6NTUuNDgzMDc1Mzk2WiJ9
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 medianet eyJVSUQiOiIzODA3NTAzNzc5Nzg2ODU1MDAwVjEwIiwiRXhwaXJlcyI6IjIwMjctMDEtMDlUMjM6MDc6NTUuNDg0Mzk4OTI1WiJ9
|
||||
.nextmillmedia.com TRUE / TRUE 1799536075 robustApps eyJVSUQiOiJkNi42ODBiMWE3ZjE1OWE0YzQ4OTIxZjM1NmI2NDJmNDdhOSIsIkV4cGlyZXMiOiIyMDI3LTAxLTA5VDIzOjA3OjU1LjU0MDYzNzYzM1oifQ==
|
||||
.nextmillmedia.com TRUE / TRUE 1799536076 zeta_global_ssp eyJVSUQiOiIxcnA2bHYyNjI3ZGIzIiwiRXhwaXJlcyI6IjIwMjctMDEtMDlUMjM6MDc6NTUuNjgwMTEwODIzWiJ9
|
||||
.nextmillmedia.com TRUE / TRUE 1799536076 unruly eyJVSUQiOiJSWC1mNjA3OTNiMS0wZWVmLTRjYTQtODJjNS1lZThhM2I1Y2RhYjktMDA1IiwiRXhwaXJlcyI6IjIwMjctMDEtMDlUMjM6MDc6NTUuODk3ODc3NjE4WiJ9
|
||||
.nextmillmedia.com TRUE / TRUE 1799536077 vidazoo eyJVSUQiOiIwNWYwNTVmNS0zY2E5LTUzNjctZjZkYS00ZWI3YTk5MTMzYzciLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1Ni42MTk3MzI3MzdaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536077 seedtag eyJVSUQiOiIwMTk3ZTgwOS0xZDI4LTc2ZmUtYmQyZS0yYTgzNjdhOWIxOTEiLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1Ni42MzA3NDc3MDZaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536077 insticator eyJVSUQiOiJjNjJkZDY0Ny0yNzNiLTQ0OTQtYmE2OS1kN2Y3NjAwNTI0YzQiLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1Ni42ODk4OTI2MjRaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536077 minutemedia eyJVSUQiOiIzOXJSX0FhY0NwX21tIiwiRXhwaXJlcyI6IjIwMjctMDEtMDlUMjM6MDc6NTYuNzg4MTA4OTIxWiJ9
|
||||
.nextmillmedia.com TRUE / TRUE 1799536077 rise eyJVSUQiOiJxN1lMVkFhY0NwX3MiLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1Ni43ODgzOTc3NzFaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536077 33across eyJVSUQiOiIyMTIzMjgyMDg2MzYxMTMiLCJFeHBpcmVzIjoiMjAyNy0wMS0wOVQyMzowNzo1Ni45MTkyNjk2NjdaIn0=
|
||||
.nextmillmedia.com TRUE / TRUE 1799536078 madopi eyJVSUQiOiJBNjc4MTQ0ODEzNTM2NDc0NjgxMCIsIkV4cGlyZXMiOiIyMDI3LTAxLTA5VDIzOjA3OjU3Ljk2NjAyMTY2MloifQ==
|
||||
.ingage.tech TRUE / TRUE 1775862476 instUid c62dd647-273b-4494-ba69-d7f7600524c4
|
||||
.ingage.tech TRUE / TRUE 1799622477 cf_clearance NCjJzyjOSrpPr8FbdKFfAf0KK4lm9mMYq9jvHHH0MR8-1768086477-1.2.1.1-mmrYg1gmneJqjVHHw9suApOL5Fp1OZNa_Www1ZEGXAncFrx3aCK6kyxZYt1wp1EWTPHaqANS5AZyQo1DXpBjc3fhm0NsRuAid0KJpU488XSwzWu1llU1Ggcb44as6HwlO.Img6iuRCK8kuU4i0G29GL0DeK3b0JrJdH26Q5oa1_wKK6IoBpZRKyoeE_kBAwsa4dnmkOWC7iAFyTiTQR2WJ2DICH4QBY3a4rvFj4PqpY
|
||||
usync.ingage.tech FALSE / TRUE 1775862470 instUid c62dd647-273b-4494-ba69-d7f7600524c4
|
||||
.admatic.de TRUE / TRUE 1802646470 uid a6d006be-43ed-4d42-8378-04d11dbce1bb
|
||||
.admatic.de TRUE / TRUE 1775862476 uids eyJ0ZW1wVUlEcyI6eyJwdWJtYXRpYyI6eyJleHBpcmVzIjoiMjAyNi0wMi0wOVQyMzowNzo1MC41NzNaIiwidWlkIjoiN0VBNTVEQUQtNUVEMS00MkRELUFGRjctOTZCMDE4N0UyRkU4In0sImFkZm9ybSI6eyJleHBpcmVzIjoiMjAyNi0wMi0wOVQyMzowNzo1MC41ODBaIiwidWlkIjoiMzg0NTk1MDc0ODA5NDc5ODMwMCJ9LCJibXRtIjp7ImV4cGlyZXMiOiIyMDI2LTAyLTA5VDIzOjA3OjUwLjU4OVoiLCJ1aWQiOiI3YjNhMGQ1Ni05Njg3LTRiNTktYjk1OS1iN2JjODJiNjhkMmEifSwibWVtYnJhbmEiOnsiZXhwaXJlcyI6IjIwMjYtMDItMDlUMjM6MDc6NTYuNzQ5WiIsInVpZCI6IjViMTk3ZDM2LWU4MjUtNGJmNi04ZTNiLWU5ZDc4NzI3OGQ5YiJ9fX0=
|
||||
pool.liftdsp.com FALSE / TRUE 1799622470 tuuid 0f4e815b-c839-410d-a8b9-575d7cbe1645
|
||||
pool.liftdsp.com FALSE / TRUE 1799622470 c 1768086470
|
||||
pool.liftdsp.com FALSE / TRUE 1799622470 tuuid_lu 1768086470
|
||||
.ib.mookie1.com TRUE / TRUE 1799622470 ibkukiuno s=89d7a4bb-c402-4bc2-a3fb-d3d8d85f8a74&h=&c=0&l=-8584335204150487532&op=&hl=0&clu=0&tcs=5&dcc=-8584638581107438250
|
||||
.id5-sync.com TRUE / TRUE 1775862470 id5 b93ab64a-793a-7025-9261-742e7bb32ab5#1766084685808#6
|
||||
.id5-sync.com TRUE / TRUE 1775862472 3pi 2#1768086471140#-1461159667|264#1768086467127#-156260550#248c815d-b156-4db9-8a92-46c25764dd54|203#1768086469599#-1560233741#6f78483e-d4c5-431a-8711-a497d0431bf7|108#1768086466841#-206138872|429#1768086472009#-1443568634#7EA55DAD-5ED1-42DD-AFF7-96B0187E2FE8|846#1768086468514#-492225994|369#1768086470445#-912217451|434#1768086470823#878225581|821#1768086471855#1728330091|441#1768086471401#1885834214#u_03cf1816-47b2-4472-8e12-9f751667d0a4|122#1768086470085#-1735519148|1242#1768086472318#-1301550593|155#1768086472167#2740117#AADBck7KgtEAABjN509uAw|796#1768086468798#-255155510|124#1768086470620#1433885824|1245#1768086470976#-1301550593
|
||||
.tribalfusion.com TRUE / TRUE 1775862472 ANON_ID aenv7yu4YUdmqcn62NoCUTPUQYIVjZapqCBi8xWYWMildQOVZcnA0qvpwhTxqqnCNZauofeoJwyZcKFRZaMIjyOkWGZas8T9INjnEbgyPV3dRPJuISMl49Zdvea
|
||||
.emxdgt.com TRUE / TRUE 1775862470 uid 47441768086470553925a6
|
||||
aorta.clickagy.com FALSE / TRUE 1802646470 chs [{"ch":"4","t":"2026-01-10 23:07:50"},{"ch":"185","t":"2025-01-24 19:59:38"},{"ch":"120","t":"2024-02-22 15:35:14"},{"ch":"8","t":"2025-07-08 03:16:33"},{"ch":"5","t":"2025-01-24 20:05:11"},{"ch":"114","t":"2025-07-08 03:16:33"},{"ch":"128","t":"2025-01-24 20:21:49"},{"ch":"124","t":"2025-01-24 20:21:49"},{"ch":"130","t":"2025-01-24 20:05:31"},{"ch":"150","t":"2025-07-08 03:16:33"}]
|
||||
.mxptint.net TRUE / TRUE 1802646471 mxpim R35CA5_10B6EE5CA_9A1777C8.1.6793F432000000006962DBC46793F20F000000006962DBC60000000000000000000000006793F51B000000006793F3FD
|
||||
.1rx.io TRUE / TRUE 1799622475 _rxuuid %7B%22rx_uuid%22%3A%22RX-f60793b1-0eef-4ca4-82c5-ee8a3b5cdab9-005%22%2C%22lastinit%22%3A%7B%222069.82%22%3A1737749787463%2C%222069.24%22%3A1737749787463%2C%222069.44%22%3A1737749787463%2C%222069.103%22%3A1737749787463%2C%222069.5%22%3A1737749787463%2C%222069.29%22%3A1737749787463%2C%222069.47%22%3A1737749787463%2C%222069.105%22%3A1737749787463%2C%222069.85%22%3A1737749787463%2C%222069.108%22%3A1737749787463%2C%222069.27%22%3A1737749787463%2C%222069.89%22%3A1737749787463%2C%222069.64%22%3A1737749787463%2C%222069.111%22%3A1737749787463%2C%222069.71%22%3A1737749787463%2C%222069.97%22%3A1737749787463%2C%222069.39%22%3A1737749787463%2C%222069.26%22%3A1737749787463%2C%222069.65%22%3A1737749787463%2C%222069.96%22%3A1737749787463%2C%222069.101%22%3A1737749787463%2C%222069.116%22%3A1737749787463%2C%222069.83%22%3A1737749787463%2C%222069.38%22%3A1737749787463%2C%222069.1%22%3A1737749787463%2C%222069.32%22%3A1737749787463%2C%222069.86%22%3A1737749787463%2C%222069.95%22%3A1737749787463%2C%222069.56%22%3A1737749787463%2C%222069.50%22%3A1737749787463%2C%222069.79%22%3A1737749787463%2C%222069.25%22%3A1737749787463%2C%222069.48%22%3A1737749787463%2C%222069.60%22%3A1737749787463%2C%222069.41%22%3A1737749787463%2C%222069.58%22%3A1737749787463%2C%222069.106%22%3A1737749787463%2C%222069.73%22%3A1737749787463%2C%222069.78%22%3A1737749787463%2C%222069.55%22%3A1737749787463%2C%222069.98%22%3A1737749787463%2C%222069.36%22%3A1737749787463%2C%222069.54%22%3A1737749787463%2C%222069.90%22%3A1737749787463%2C%222069.112%22%3A1737749787463%2C%222069.74%22%3A1737749787463%2C%222069.49%22%3A1737749787463%2C%222069.43%22%3A1737749787463%2C%222069.10%22%3A1737749787463%2C%222069.104%22%3A1737749787463%2C%222069.102%22%3A1737749787463%2C%222069.61%22%3A1737749787463%2C%222069.113%22%3A1737749787463%2C%222069.87%22%3A1737749787463%2C%222069.66%22%3A1737749787463%2C%222069.80%22%3A1737749787463%2C%222069.46%22%3A1737749787463%2C%222069.6%22%3A1737749787463%2C%222069.31%22%3A1737749787463%2C%222069.59%22%3A1737749787463%2C%222069.109%22%3A1737749787463%2C%222069.114%22%3A1737749787463%2C%222069.115%22%3A1737749787463%2C%222069.72%22%3A1737749787463%2C%222069.63%22%3A1737749787463%2C%222069.91%22%3A1737749787463%2C%222069.42%22%3A1737749787463%2C%222069.35%22%3A1737749787463%2C%222069.110%22%3A1737749787463%2C%222069.34%22%3A1737749787463%2C%222069.57%22%3A1737749787463%2C%222069.88%22%3A1737749787463%2C%222069.28%22%3A1737749787463%2C%222069.92%22%3A1737749787463%7D%2C%22lastsyncall%22%3A1737749787463%7D
|
||||
.admixer.net TRUE / TRUE 1775862476 am-uid 0f98d334640144d587d3b02ce049917a
|
||||
.adtelligent.com TRUE / TRUE 1776121677 vmuid 83a3bef4fbbf98a8
|
||||
server.smartytech.io FALSE / TRUE 1799622477 uid 3178aeee-de98-4209-9cd5-4a93fc663b44
|
||||
.rlcdn.com TRUE / TRUE 1799622478 rlas3 e/vV39S5p8q+XmmJZtjqYThcGcHi7BVfVwyFmwHekVdZZsLG1/Iz4RUpjoH9aGnHLho0Dk8C2wraaHJYoyT7csQFaIEszxKbBusappoLnpWJwynr2TGyGHQiET1cZU4aVRk0gAef9x0l3cL68Ah80sfJhjGRHbtBQemD/FHkryqMyA9jEACu5w==
|
||||
.ow.pubmatic.com TRUE / TRUE 1775862477 uids eyJ0ZW1wVUlEcyI6eyJhbXgiOnsidWlkIjoiNjY5NGRlM2YtYTRlNC00MTUzLWJlOTAtMzgwNzBmMzIyYzc2IiwiZXhwaXJlcyI6IjIwMjYtMDEtMjRUMjM6MDc6NTcuMzM1NTgwNjkzWiJ9fX0=
|
||||
.tynt.com TRUE / TRUE 1775862477 pids %5B%7B%22p%22%3A%22797f54a72d%22%2C%22f%22%3A1%2C%22ts%22%3A1768086466511%7D%2C%7B%22p%22%3A%22f46c881bee%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469697%7D%2C%7B%22p%22%3A%224bee518595%22%2C%22f%22%3A1%2C%22ts%22%3A1768086468893%7D%2C%7B%22p%22%3A%226f27415d53%22%2C%22f%22%3A1%2C%22ts%22%3A1768086468893%7D%2C%7B%22p%22%3A%227daaa56bb0%22%2C%22f%22%3A1%2C%22ts%22%3A1768086468893%7D%2C%7B%22p%22%3A%227912d88d74%22%2C%22f%22%3A1%2C%22ts%22%3A1768086468893%7D%2C%7B%22p%22%3A%22d9fe068602%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469809%7D%2C%7B%22p%22%3A%22f5b8438f72%22%2C%22f%22%3A1%2C%22ts%22%3A1768086468893%7D%2C%7B%22p%22%3A%22fcb82aaae3%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469809%7D%2C%7B%22p%22%3A%22607295b4a4%22%2C%22f%22%3A2%2C%22ts%22%3A1768086474638%7D%2C%7B%22p%22%3A%223bfd58deb3%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469697%7D%2C%7B%22p%22%3A%22baebe6454b%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469697%7D%2C%7B%22p%22%3A%220f90caf3cf%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469697%7D%2C%7B%22p%22%3A%22162dbd77b3%22%2C%22f%22%3A1%2C%22ts%22%3A1768086466511%7D%2C%7B%22p%22%3A%226db3fb8a85%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469697%7D%2C%7B%22p%22%3A%22b32ef6f991%22%2C%22f%22%3A23%2C%22ts%22%3A1768086477380%7D%2C%7B%22p%22%3A%22002f98d420%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469809%7D%2C%7B%22p%22%3A%2224c05c7b76%22%2C%22f%22%3A1%2C%22ts%22%3A1768086466511%7D%2C%7B%22p%22%3A%22cf4d6e49b5%22%2C%22f%22%3A1%2C%22ts%22%3A1768086466511%7D%2C%7B%22p%22%3A%2222833ea406%22%2C%22f%22%3A1%2C%22ts%22%3A1768086468893%7D%2C%7B%22p%22%3A%225cb91279ed%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469697%7D%2C%7B%22p%22%3A%22f9a4a8fd15%22%2C%22f%22%3A1%2C%22ts%22%3A1768086466511%7D%2C%7B%22p%22%3A%22008c314e8f%22%2C%22f%22%3A1%2C%22ts%22%3A1768086466511%7D%2C%7B%22p%22%3A%22729ff3013e%22%2C%22f%22%3A1%2C%22ts%22%3A1768086469809%7D%5D
|
||||
.exelator.com TRUE / TRUE 1778454480 EE "cc59f09a65a8447a5cf59d53c2ba71ef"
|
||||
.exelator.com TRUE / TRUE 1778454480 ud "eJxrXxzq6XKLQSE52dQyzcAy0cw00cLExDzRNDnN1DLF1DjZKCnR3DA1bXFZatGCpaXFqSlJh5ZU5JTkNK0uiw91jHdz9PX0iVzmnFGUn5u6AiwU5hq02NDEeEl%252BUWb6otDgxUUpaQyLSopPBZ%252B9KgoAxksq1g%253D%253D"
|
||||
.exelator.com TRUE / TRUE 1778454480 hsk_7144 "gAAAAAQAAABqKLUv%252FSBqUQMAiKRidWlkuWYzcmRoYm1xdHptYmdmYzg2NnEwNjg0a2mjaHNrpDY5NDmoZGVsaXZlcnmkNjk0OaN2ZXIBpWJuYW1lqFMyMDRVMjJWpXRzZWdzpzI4NTU5ODKlYmNvZGXNG%252BiidHPKU83VFQ%253D%253D"
|
||||
.e-planning.net TRUE / TRUE 1802646477 E ALz5R0Mx61BTzRqq
|
||||
pbs-publift-us.ay.delivery FALSE / TRUE 1775862477 uids eyJ0ZW1wVUlEcyI6eyIzM2Fjcm9zcyI6eyJ1aWQiOiIyMTIzMjgyMDg2MzYxMTMiLCJleHBpcmVzIjoiMjAyNi0wMS0yNFQyMzowNzo0Ni42Nzk0Mzc1MjZaIn0sImFkbnhzIjp7InVpZCI6IjE0NDY2NjQ2MzMwNjI0NTU3MzgiLCJleHBpcmVzIjoiMjAyNi0wMS0yNFQyMzowNzo1MC42MjIxNDgwNjZaIn0sImFteCI6eyJ1aWQiOiI2Njk0ZGUzZi1hNGU0LTQxNTMtYmU5MC0zODA3MGYzMjJjNzYiLCJleHBpcmVzIjoiMjAyNi0wMS0yNFQyMzowNzo1My42Mjg5OTY4OVoifSwia3VlZXpydGIiOnsidWlkIjoiNjZlODI5MjEtMjViOS1kZGM4LWM2MjYtZTU0ZjY3MTA2Mjk5IiwiZXhwaXJlcyI6IjIwMjYtMDEtMjRUMjM6MDc6NTIuNzE1MDkxNDA5WiJ9LCJtZWRpYW5ldCI6eyJ1aWQiOiIzODA3NTAzNzc5Nzg2ODU1MDAwVjEwIiwiZXhwaXJlcyI6IjIwMjYtMDEtMjRUMjM6MDc6NTcuNDExNTg0NzY2WiJ9LCJvcGVueCI6eyJ1aWQiOiJkNjk4MWFlNy00ZWE1LTQ5NjUtODVjNi0zNDUzYTdjMDE0NTYiLCJleHBpcmVzIjoiMjAyNi0wMS0yNFQyMzowNzo1MS42MTUyNzc0NTVaIn0sInB1Ym1hdGljIjp7InVpZCI6IjdFQTU1REFELTVFRDEtNDJERC1BRkY3LTk2QjAxODdFMkZFOCIsImV4cGlyZXMiOiIyMDI2LTAxLTI0VDIzOjA3OjUzLjg1NDE5NTExM1oifSwic2VlZHRhZyI6eyJ1aWQiOiIwMTk3ZTgwOS0xZDI4LTc2ZmUtYmQyZS0yYTgzNjdhOWIxOTEiLCJleHBpcmVzIjoiMjAyNi0wMS0yNFQyMzowNzo0NS41NjkzNTkwMzVaIn0sInZpZGF6b28iOnsidWlkIjoiMDVmMDU1ZjUtM2NhOS01MzY3LWY2ZGEtNGViN2E5OTEzM2M3IiwiZXhwaXJlcyI6IjIwMjYtMDEtMjRUMjM6MDc6NTQuNjM3ODUwNjk3WiJ9fX0=
|
||||
.brand-display.com TRUE / TRUE 1798600578 _knxq_ 0c3b7d5a-56ff-e9a3-fb4fc63f.1751944578.2.1768086477.1751944662
|
||||
.adtarget.biz TRUE / TRUE 1775862477 uids eyJ0ZW1wVUlEcyI6eyJwdWJtYXRpYyI6eyJleHBpcmVzIjoiMjAyNi0wMi0wOVQyMzowNzo1Ny41NDhaIiwidWlkIjoiN0VBNTVEQUQtNUVEMS00MkRELUFGRjctOTZCMDE4N0UyRkU4In0sImFkZm9ybSI6eyJleHBpcmVzIjoiMjAyNi0wMi0wOVQyMzowNzo1Ny41NTRaIiwidWlkIjoiMzg0NTk1MDc0ODA5NDc5ODMwMCJ9LCJibXRtIjp7ImV4cGlyZXMiOiIyMDI2LTAyLTA5VDIzOjA3OjU3LjU4NVoiLCJ1aWQiOiI3YjNhMGQ1Ni05Njg3LTRiNTktYjk1OS1iN2JjODJiNjhkMmEifX19
|
||||
.adtarget.biz TRUE / TRUE 1802646478 uid 03f75d14-552e-4ca8-8bfd-041dbccd6bbb
|
||||
.analytics.yahoo.com TRUE / TRUE 1799622478 IDSYNC "173n~2n5s:175s~2n57:175w~2hsn:1769~2el6:176l~2n5c:18vk~2g2j:18xa~2hsn:18y3~2gwf:18yi~2n57:18yl~2q6r:18yo~2g2j:18z8~2q6r:18z9~2hx1:18za~2hsn:190u~2n57:191q~2gwf:1929~2hx1:193k~2gwf:194o~2gwf:195g~2gce:1967~2hsn:1969~2tnb:196y~2hsn:199z~2nh7:19ab~2t7v:19ac~2n58:19aj~2lpr:19b9~2nf8:19bh~2gwf:19bk~2n5f:19bn~2lpr:19bu~2lpr:19bx~2f7r:19cg~2n58:19cu~2lpr:19cw~2lpr:19cx~2hsn:19e0~2lpr:19e3~2g2j:19e7~2lpr:19ea~2lpr:19ai~2n57:19cl~2tnb:19ba~2n58:17mv~2n58:173h~2n58:19h2~2tnb:19gl~2tnb:19h3~2tnb:19h0~2tnb"
|
||||
.pro-market.net TRUE / TRUE 1783638478 anProfile "jivjmz9he9gc+1+4=2m3+1f=1+1g=1+1j=57:1+rs=s+rt=26001700477AB01084F88A9E2C958264+s0=(a)+s2=(t7j7y3)+vm=47-87fd5a53-dc6b-4dcd-a287-48e386f3b8f1:67-64651016430244522174023048184620348074"
|
||||
.pbs.yahoo.com TRUE / TRUE 1783811278 uids eyJ0ZW1wVUlEcyI6eyJ0cmlwbGVsaWZ0Ijp7InVpZCI6IjEwOTU5MTc5MDk3OTUxNjg5NjcxNzAiLCJleHBpcmVzIjoiMjAyNi0wMS0yNFQyMzowNzo1OC4yNzcwMzY3NDJaIn19fQ==
|
||||
.thrtle.com TRUE / TRUE 1785366478 mc eyJpZCI6IjdmNzFiNjVlLWQ5NjUtNDJjNC1hOWMyLTI3NTdmY2NjNWU2MCIsImwiOjE3NjgwODY0NzgzNTMsInQiOjI2OH0=
|
||||
.thrtle.com TRUE / TRUE 1785366478 sc eyJpIjoiZDg4NjkzNjAtZDlhZS00ODdkLTg2OGQtMDhjYmM1ZTg4YTMyIiwic2lkIjoic2lkLTM0M2ZjMzcxLWVlNzktMTFmMC1hOWJiLTAyNDIwYWZmMTViOSIsIm1zIjoyLCJwcyI6MTMsImxwIjo1MDQ3LCJzcCI6NTA0NCwicHAiOjEzLCJ0c2UiOjMxLCJsdHNlIjoxNzY4MDg2NDc4MTY4fQ==
|
||||
.clawi.ai TRUE / TRUE 1801951338 __stripe_mid 90fabc42-c1f3-4d66-9c87-5c4f03ef73f5cf7b18
|
||||
getalby.com FALSE / FALSE 1778527919 login_method otp
|
||||
claude.ai FALSE / TRUE 1797201511 anthropic-device-id 534e1c34-4f23-40c6-8112-a7903ca8884e
|
||||
claude.ai FALSE / FALSE 1805841472 _fbp fb.1.1771281471505.62904287848319980
|
||||
claude.ai FALSE / FALSE 1786833474 g_state {"i_l":0,"i_ll":1771281474848,"i_b":"m99XCDLAoL8P11crnbjIezvOZZdvtUX0Hgfq8LNtsLM","i_e":{"enable_itp_optimization":14}}
|
||||
.claude.ai TRUE / FALSE 1802817511 ajs_anonymous_id claudeai.v1.bbd65f09-a89f-4ba0-8d3a-765e242e7b59
|
||||
.claude.ai TRUE / TRUE 1802817511 CH-prefers-color-scheme light
|
||||
.claude.ai TRUE / FALSE 1805841473 __ssid 7aeefe83-85be-4b98-b9c0-b4f73844ccb6
|
||||
.claude.ai TRUE / TRUE 1802817511 lastActiveOrg 3a9dd5ca-f997-4fac-928b-86c0d8256273
|
||||
.claude.ai TRUE / TRUE 1794611513 intercom-device-id-lupk8zyo b53ff69c-4e9f-484c-8824-5fedc4acb6ee
|
||||
.claude.ai TRUE / FALSE 1802817511 ajs_user_id d578b8e1-704f-49a3-a691-67538a600e48
|
||||
.claude.ai TRUE / TRUE 1802817511 cf_clearance Rhus4wvo7dTBFd9IdHj04VerNdQBvsLf4BSmR14P62M-1771281511-1.2.1.1-ApqfCOEl1m3Oi1wan95HTIr95afvB2d_xsRrruPB22RIc5RprR8gAv6Nsr1j.CKzzXLHNCX5UbsVvPnMYeEBQl6UszA8_k3Osf4PV.fXVu.2OYBHufWxS1iSWDBMRVsp_Ela_O._hctK7IGx9oWnoDAHaybY3SIDZx3bk_yjcy0.vURxhX0roinh8l37XhgxYYtxH77yryXASwc.z0ZEWi94Oks0TpNiRDNAQDQzyIg
|
||||
immense-voyage.local FALSE / FALSE 1807808010 session jt3ax4vz67rvx4hwcccryo2bna
|
||||
5.161.191.254 FALSE / FALSE 1807828861 session mrnehylzg5pod7utyx7ykyitgy
|
||||
secure.chase.com FALSE / FALSE 1804898020 ktlvDW7IG5ClOcxYTbmY a
|
||||
chromewebstore.google.com FALSE / TRUE 1776279448 OTZ 8523057_76_80_104160_76_446820
|
||||
ogs.google.com FALSE / TRUE 1776279489 OTZ 8523058_76_80_104160_76_446820
|
||||
accounts.google.com FALSE / TRUE 1776285616 OTZ 8523160_76_80_104160_76_446820
|
||||
accounts.google.com FALSE / TRUE 1808253661 ACCOUNT_CHOOSER AFx_qI64Fyd3WOgqzqEwirImDYclCyKBdomLnpImNfCbXy-ToyYOZLOQM6BhSmSlh7UFNCDPjszdP-z3uKjvrdOfLvtfp1F6Kg2wUiy8bAxCN7gdW25-ySdXdN2M4W1pBJex8Gf5FSrR
|
||||
accounts.google.com FALSE / TRUE 1808253661 __Host-GAPS 1:RmYuBFSvtOYIoZSDApEcQTWRxTxxAOhQ7SWZ8-9OvRL405mb07I9hfesu8FtVAqHJcpnT5c1Yg0gdUg3wuOLqIyLqhKkJg:PNT2SoEsKh2Qqkj0
|
||||
accounts.google.com FALSE / TRUE 1808253661 SMSV ADHTe-DkkvBH6NujmTV1-jzXXvTKEoeb5sPPlOpFf60Ao3D66REzOEbHCQR1fWFuMkepvsaFR9tW8bz_UbR-t5hVK1ef7KuL3vlIIU9rx8ybr1mBFe0XlwQ
|
||||
accounts.google.com FALSE / TRUE 1808253661 LSID s.youtube:g.a0007whSQ6uWt7O_xuWCIoHK_EdxOWsKkMphXjhgD52Z_0oaIFM-FJpJ_APy6iex2KGtKZTfMAACgYKAfASARMSFQHGX2MipyYBdH9B1sm4C82pTF10MhoVAUF8yKqMdmN7-ALswzn7C2ZHpz0g0076
|
||||
accounts.google.com FALSE / TRUE 1808253661 __Host-1PLSID s.youtube:g.a0007whSQ6uWt7O_xuWCIoHK_EdxOWsKkMphXjhgD52Z_0oaIFM-xChahLJ-oWsMFMsal1AN-gACgYKAeYSARMSFQHGX2Mi6WdZ1kGkd18xVbcWRxA_mxoVAUF8yKoV_PIQM3B0ISl_lr7KTTmu0076
|
||||
accounts.google.com FALSE / TRUE 1808253661 __Host-3PLSID s.youtube:g.a0007whSQ6uWt7O_xuWCIoHK_EdxOWsKkMphXjhgD52Z_0oaIFM-U7S3MQ5V_ZeYOlCxJ_8x2wACgYKAf8SARMSFQHGX2Mi6DaJTk2e9IEPdfrMYUlALhoVAUF8yKoUhbRHHVSlePzvMBFRGxc40076
|
||||
.youtube.com TRUE / FALSE 1808253662 HSID ASVnILepE6lKhaVKT
|
||||
.youtube.com TRUE / TRUE 1808253662 SSID AOW01b5NEUFzESSgG
|
||||
.youtube.com TRUE / FALSE 1808253662 APISID MdMQfFFo_4b0Cw2d/Au_xxzGsUXCUZnFia
|
||||
.youtube.com TRUE / TRUE 1808253662 SAPISID gAA5ERfoktTnNYkF/A7x17szT_7WqXM9A1
|
||||
.youtube.com TRUE / TRUE 1808253662 __Secure-1PAPISID gAA5ERfoktTnNYkF/A7x17szT_7WqXM9A1
|
||||
.youtube.com TRUE / TRUE 1808253662 __Secure-3PAPISID gAA5ERfoktTnNYkF/A7x17szT_7WqXM9A1
|
||||
.youtube.com TRUE / FALSE 1808253662 SID g.a0007whSQ2FTtN3oaH2z5zAUg7rUNnJXuBC-FtNcmf_q4VZxCH6I5yCVYxA-LmPOHRXLgQktwAACgYKASYSARMSFQHGX2MitoydJ2nBzhSIkt8ceGNDPRoVAUF8yKpvGQGXHR2ixssAhIZ7Tlhg0076
|
||||
.youtube.com TRUE / TRUE 1808253662 __Secure-1PSID g.a0007whSQ2FTtN3oaH2z5zAUg7rUNnJXuBC-FtNcmf_q4VZxCH6IIWYz6SgNFiNwCFav4fBlxgACgYKAZgSARMSFQHGX2MiUhFl0FoKqeIalNYwK9r2kRoVAUF8yKquv1J4_ggvLRhNHGom3rco0076
|
||||
.youtube.com TRUE / TRUE 1808253662 __Secure-3PSID g.a0007whSQ2FTtN3oaH2z5zAUg7rUNnJXuBC-FtNcmf_q4VZxCH6Ip1KVQpXe0-3wXj_r0kABhgACgYKAVESARMSFQHGX2MiaYklqIL3lhBMrkEcEBXS5RoVAUF8yKpcc98ulcMv04cCcRloUdNL0076
|
||||
.youtube.com TRUE / TRUE 1808253662 LOGIN_INFO AFmmF2swRQIgDa8cIvI1fxFdd3GEA2GvmAmbS0amlSptrhn2SsGlEa0CIQCaL131LVEaQj7oJl3R9r7ONED30oCInRpvUDrLrbviyQ:QUQ3MjNmd3gxTkhRRmdRbC1Bb19lVDB2Znh0NzN0S2NmaGF5b0ZiNGlrdGpXOF8teVF1Q1ZzdHVuMmZtMVJNb1N4OVZVX0Y4MTRmbXZDTGdDaVpPRVo5YmJxSHVjT2FHOG01NkhzYmJsbTlSdEFZc0s4bFB5SWk5WlhNTWZzTmNPcEd4a01vY04tcVVuaEVWUjFWcTdveGVURDhldGtYU1Vn
|
||||
.youtube.com TRUE / FALSE 0 PREF f6=80&f7=4100&hl=en&tz=UTC
|
||||
.youtube.com TRUE / TRUE 1806760505 __Secure-1PSIDTS sidts-CjQBWhotCRA5YMKYuDyG5wumZa4VFuY3F7Fh2duwXD0UmuF6N7mEL_UYQOvz_1NTpoI1B-f4EAA
|
||||
.youtube.com TRUE / TRUE 1806760505 __Secure-3PSIDTS sidts-CjQBWhotCRA5YMKYuDyG5wumZa4VFuY3F7Fh2duwXD0UmuF6N7mEL_UYQOvz_1NTpoI1B-f4EAA
|
||||
.youtube.com TRUE / FALSE 1807301008 SIDCC AKEyXzUUyF0XN5paW4VLY0NtxejSk0M28OtfHP5n4n5pOvmXQZyuMzKtfpKiNzQdoxyuNYzuog
|
||||
.youtube.com TRUE / TRUE 1807301008 __Secure-1PSIDCC AKEyXzUKO_KXpaA8y_dIx4hE0QqX4gfoqvsJg_JCzh5xMDXVTRzzXQWoHvptSZthdcHfYa15NA
|
||||
.youtube.com TRUE / TRUE 1807301008 __Secure-3PSIDCC AKEyXzURyWvFIoT3UnuYN9789UBC3QqMjdjMkg4gfrVyPT5SQOJwjtlYGwRzqd0HCuQeYSwdjxY
|
||||
.youtube.com TRUE / TRUE 1791317008 VISITOR_INFO1_LIVE ENb1E2-qMSc
|
||||
.youtube.com TRUE / TRUE 1791317008 VISITOR_PRIVACY_METADATA CgJVUxIEGgAgUg%3D%3D
|
||||
.youtube.com TRUE / TRUE 1791313395 __Secure-ROLLOUT_TOKEN CLav7oDA64mAEBDv_MPOo6WTAxiar9XZuuGTAw%3D%3D
|
||||
.youtube.com TRUE / TRUE 1780182149 __Secure-YNID 13.YT=uPn267RhS6_DPP8X1r3X0mUsAq8X0L4zeknD1-ypQ02nK4yp2NT8iig-SVdbf_A0GP18-P4CgEglD8GsSkPjJVXW0IPFBWBykHuwczveAI30caCVgCUue4RQg2a9nLaU0s1BA2YJRygITXiXP7DGUp4lUDUhfK8-AEdzSeF_NcrFxnhs1lSzfO-og_isBQuS1O3Mv-kcOPgdkhUGWl4ZbIazInJka_fj45KQYi0IpoyMATQrN21FBdpCB-elz4s0Jk7cSB265FSf9McS8oQf0jIEW3pRbBJ2gTYIv5CDgJBGde-A43F8W2QnG2FLgc8huPihY9duf8fWyL6P9a5YLw
|
||||
.youtube.com TRUE / TRUE 0 YSC JFh3yO0TPqY
|
||||
.youtube.com TRUE / TRUE 1791138263 __Secure-BUCKET CLwC
|
||||
.evenue.net TRUE / FALSE 1805835847 _pxvid d4560d49-26fb-11f1-b9e0-54cb44a244a8
|
||||
.evenue.net TRUE / FALSE 1782075847 _gcl_au 1.1.1393764598.1774299847.623268785.1774299856.1774299860
|
||||
.evenue.net TRUE / FALSE 1808859865 _ga GA1.1.1833572337.1774299847
|
||||
.evenue.net TRUE / FALSE 1808859904 _ga_PXLJRLJD73 GS2.2.s1774299863$o1$g1$t1774299903$j20$l0$h0
|
||||
.evenue.net TRUE / FALSE 1808859919 _ga_VKEY0CCQPT GS2.1.s1774299847$o1$g1$t1774299918$j60$l0$h0
|
||||
goduke.evenue.net FALSE / TRUE 1805835891 WTPERSIST
|
||||
.adserver.inflightinternet.com TRUE / TRUE 1806510262 _ab_csid I0uhQm5%2BD3xbp97Js5KciY23Ok%2BiFXpu1ON3j7FZpOeWyNm2FpUYDmDCZnGw9%2F2K
|
||||
www.aa.com FALSE / TRUE 0 XSRF-TOKEN d26ece12-58b2-44b5-a96d-845c65813ef1
|
||||
www.aa.com FALSE / TRUE 0 JSESSIONID 567F2ABD5E672A0A33951C9664299FD8
|
||||
www.aa.com FALSE / TRUE 0 aka_state_code VA
|
||||
www.aa.com FALSE / TRUE 0 aka_cr_code US-VA
|
||||
www.aa.com FALSE / TRUE 0 sessionLocale en_US
|
||||
www.aa.com FALSE / TRUE 1777566385 al 0
|
||||
www.aa.com FALSE / TRUE 0 akavpau_www_aahomepage 1774974685~id=fc154d22d03c3f02c71c83c7d63a71fd
|
||||
www.aa.com FALSE / FALSE 0 aka_lc_code ML
|
||||
www.aa.com FALSE / TRUE 0 KROUTEID c4386c20c7a71c8b98ea571950b9023a|b1f37ed7f54333e7fed5541bf6553ced
|
||||
www.aa.com FALSE / TRUE 0 akavpau_www_aafullsite 1775224801~id=f1411d92597cd0576b28f85835e74fcd
|
||||
.www.aa.com TRUE / TRUE 1809534305 UAC 9660f397662842c9a5749fba1d2f34e8
|
||||
.aa.com TRUE / FALSE 0 rxVisitor 1774974462693TUVBMAUPSSLQG9LF1C8ENSS7P6ILAHIQ
|
||||
.aa.com TRUE / FALSE 0 dtSa -
|
||||
.aa.com TRUE / FALSE 0 dtCookie v_4_srv_16_sn_A6ED5A1920AD6C3AD36860C6EDA12B81_perc_100000_ol_0_mul_1_app-3A8b2a7e44ceb3fcd4_1_rcs-3Acss_0
|
||||
.aa.com TRUE / TRUE 1806759886 _abck 67380BEE96080DB117362BC3756BEA8C~-1~YAAQ5z3XF5a6iU2dAQAAKdCWUw/lBEKoHIIuWNYVmSiEDSpN5SyK9zGRg/U8PWg/ZCWVoBmFWJrfI94Yl876rAcDEOa7TXBbFPn93vnqoctznmL8dY8WdEdvJnIkZEGSDR92SLMD5eI4WbkLfGj6/ddv1TUZwKb7scYA7fCMvdE/Siib2YMIljMZgIKRDZA8w9bffKSTVntv8Tkiuq/DArqM+FnRvPKmI1qckwPbAmFc1zF67Nb7OOYkV36UZZmt7dJyKi0v+Zz9w58AWPXnoFLUKGuM34+O6yCs6qSRGxv+XrIe60ZUfmv1ent01YraNiGhC8sE1S4NOtt02nP6QU2sCg8cm/02tX7KX2jG85xqs/AW6u+QUmSgVqKfFTjksp6L0Ii2bBbY/Ru9YdlNeeZutmAQmns5al7+BPrEdCIqL4yimCyCU2y6IFbNYyUYgtz4ibjVqlFjad1HUAR1LInf~-1~-1~-1~-1~-1
|
||||
.aa.com TRUE / FALSE 0 dtsrVID 1775147472723
|
||||
.aa.com TRUE / FALSE 0 rxvt 1775149281085|1775146868389
|
||||
.aa.com TRUE / FALSE 0 dtPC 16$174462690_847h-vFJCRQWUFVIVJAVFKCRWLMPIAARUNADFH-0e0
|
||||
.doubleclick.net TRUE / TRUE 1809784503 IDE AHWqTUlisU2hmqPtDHgMSndCiEYb0PgfGDl4xaG6WQuM9aCEwjWFA-s7tqw9EZDh
|
||||
.doubleclick.net TRUE / TRUE 1783638469 APC AfxxVi6hNvQV29SLhzAFSpJ9ITzn0e3Wg50VHJGNpgewSpGfGZILqQ
|
||||
.protechts.net TRUE / TRUE 1781649266 _pxvid 0ed20029-4b02-11f0-942d-350be9935237
|
||||
.protechts.net TRUE / TRUE 1784385137 _px3 ff2e7f344e23124464181eb32a6547e8885afa2278f627d84c416eaa11765b2a:tEM1lQYPDIr7NIsSjXWJ26RKR1lKMP7Hq3mYq1PoOBjAT5hIQrofQYfUdbwKqECGvlfP42qmFno1iQBvlNuJbQ==:1000:7qGM1VmYIh4dHQ/0zkiQ11NC3Hly4knCGG1cM8RvU+GQcTtlRjayPpoTnJjspPvW0lgpzFNEUMkS2aDaxgVk5kQK+9HLuNcZXsxQtS5nZFLa7IWj7oGoPC4tlzi5XkBhgo8jZY+kvV7+WjKQoe4bzoJl0Si26iMlzeh3OtCpxkqFsOzlZ7i9j0COaEouvXsP8f06JnJwdn/6jfE8CJZbb2Bk0ivQkw61FEKzJAKH/lE=
|
||||
.criteo.com TRUE / TRUE 1785640562 receive-cookie-deprecation 1
|
||||
.criteo.com TRUE / TRUE 1801782514 cto_bundle BW3AuV84ODVyMXZkYTg2T2R5YjRwTVI0Y3lRT1pqTU44RUVoWWcxQ29xczVWYm5wVkhodktxQzJDd0V1eGhtOGxrZ2N1Y0ZSVkdLTVh1WDNVd1ZMTjByNGZDQktQQjVLdkxKVTc1ZE1MbDB6RjB0U1VoZ0Fwc3VSSVlTTHkzWmpFRDVTNmNmVlNEVFBiVk9haTJwQlRDMEsyZEElM0QlM0Q
|
||||
top-fwz1.mail.ru FALSE / TRUE 1787328588 PVID 24Phk500X52Y0026Kk1Q01oY:::0-0-0-cae53fc-0-dc04c0c:CAASEKxMyii6AT78_-3NUPqD0UIaYHtsqvds-0kSklpezGsuCNzWPVpfXllbLL1vqX4f428ZW2vUxODue-givca9Uz03dLH8ZLOAeFiLjUWT2D7xIKjFSSw1mNF8GXEjOnpIeFEPmwLXqAyKewzaUgOzLS9SFg
|
||||
prebid.media.net FALSE / TRUE 1783638514 receive-cookie-deprecation 1
|
||||
.tracookiepixel.xyz TRUE / TRUE 1799622469 server_tracking_bdsp_uid AADBck7KgtEAABjN509uAw
|
||||
Executable
+194
@@ -0,0 +1,194 @@
|
||||
#!/bin/bash
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Creates "YouTube Summarizer.app" — a proper macOS app bundle
|
||||
# that you can put in your Dock, Desktop, or Applications folder.
|
||||
#
|
||||
# Usage: Run this once from the project folder:
|
||||
# chmod +x create-app.sh && ./create-app.sh
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
APP_NAME="YouTube Summarizer"
|
||||
APP_PATH="$PROJECT_DIR/$APP_NAME.app"
|
||||
|
||||
echo ""
|
||||
echo "Creating $APP_NAME.app..."
|
||||
echo ""
|
||||
|
||||
# ── Build the .app bundle structure ──────────────────────────
|
||||
rm -rf "$APP_PATH"
|
||||
mkdir -p "$APP_PATH/Contents/MacOS"
|
||||
mkdir -p "$APP_PATH/Contents/Resources"
|
||||
|
||||
# ── Create the launcher script ───────────────────────────────
|
||||
cat > "$APP_PATH/Contents/MacOS/launcher" << 'LAUNCHER'
|
||||
#!/bin/bash
|
||||
|
||||
# Resolve the real project directory (the .app lives inside it)
|
||||
APP_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
|
||||
|
||||
# If the app has been moved (e.g. to /Applications), check for a saved path
|
||||
SAVED_PATH="$HOME/.config/youtube-summarizer/project-path"
|
||||
if [ ! -f "$APP_DIR/server/index.js" ]; then
|
||||
if [ -f "$SAVED_PATH" ]; then
|
||||
APP_DIR="$(cat "$SAVED_PATH")"
|
||||
else
|
||||
# Ask the user to locate the project folder
|
||||
APP_DIR=$(osascript -e 'POSIX path of (choose folder with prompt "Locate your YouTube Summarizer project folder:")')
|
||||
APP_DIR="${APP_DIR%/}"
|
||||
if [ -z "$APP_DIR" ] || [ ! -f "$APP_DIR/server/index.js" ]; then
|
||||
osascript -e 'display alert "YouTube Summarizer" message "Could not find the project folder. Make sure server/index.js exists." as critical'
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$(dirname "$SAVED_PATH")"
|
||||
echo "$APP_DIR" > "$SAVED_PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$APP_DIR"
|
||||
|
||||
# Add common Homebrew paths (node, yt-dlp)
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
|
||||
|
||||
# Check for Node.js
|
||||
if ! command -v node &> /dev/null; then
|
||||
osascript -e 'display alert "YouTube Summarizer" message "Node.js is not installed. Install it with: brew install node" as critical'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for yt-dlp
|
||||
if ! command -v yt-dlp &> /dev/null; then
|
||||
if command -v brew &> /dev/null; then
|
||||
brew install yt-dlp 2>&1
|
||||
else
|
||||
osascript -e 'display alert "YouTube Summarizer" message "yt-dlp is not installed. Install it with: brew install yt-dlp" as critical'
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install npm dependencies if needed
|
||||
if [ ! -d "server/node_modules" ]; then
|
||||
cd server && npm install && cd ..
|
||||
fi
|
||||
|
||||
# Ask user: Home or Traveling?
|
||||
ICON_PATH="$APP_DIR/assets/icon.png"
|
||||
NETWORK_CHOICE=$(osascript -e "
|
||||
set iconFile to POSIX file \"$ICON_PATH\"
|
||||
set theChoice to button returned of (display dialog \"Where are you right now?\" & return & return & \"Home — allows your phone and other devices on your Wi-Fi to use the app.\" & return & return & \"Traveling — locks access to just this laptop for safety on public Wi-Fi.\" buttons {\"Traveling\", \"Home\"} default button \"Traveling\" with title \"YouTube Summarizer\" with icon iconFile)
|
||||
return theChoice
|
||||
" 2>/dev/null)
|
||||
|
||||
# Default to traveling (safe) if dialog was cancelled
|
||||
if [ "$NETWORK_CHOICE" = "Home" ]; then
|
||||
export LAN_MODE=true
|
||||
else
|
||||
export LAN_MODE=false
|
||||
fi
|
||||
|
||||
# Kill any existing instance on port 3001
|
||||
lsof -ti:3001 | xargs kill -9 2>/dev/null
|
||||
sleep 0.3
|
||||
|
||||
# Start the server
|
||||
cd server
|
||||
node index.js &
|
||||
SERVER_PID=$!
|
||||
cd ..
|
||||
|
||||
# Wait for server to be ready (up to 10 seconds)
|
||||
for i in {1..20}; do
|
||||
if curl -s http://localhost:3001/api/health > /dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
# Open browser
|
||||
open http://localhost:3001
|
||||
|
||||
# Keep alive — when the app is quit, stop the server
|
||||
trap "kill $SERVER_PID 2>/dev/null; exit 0" INT TERM
|
||||
wait $SERVER_PID
|
||||
LAUNCHER
|
||||
|
||||
chmod +x "$APP_PATH/Contents/MacOS/launcher"
|
||||
|
||||
# ── Create Info.plist ────────────────────────────────────────
|
||||
cat > "$APP_PATH/Contents/Info.plist" << PLIST
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>launcher</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>YouTube Summarizer</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.local.youtube-summarizer</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>AppIcon</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
PLIST
|
||||
|
||||
# ── Create the app icon from the pre-made PNG ───────────────
|
||||
ICON_PNG="$PROJECT_DIR/assets/icon.png"
|
||||
ICON_DIR="$APP_PATH/Contents/Resources"
|
||||
|
||||
if [ -f "$ICON_PNG" ]; then
|
||||
echo "Building app icon..."
|
||||
|
||||
# Create iconset with all required sizes using sips (built into macOS)
|
||||
ICONSET="$ICON_DIR/AppIcon.iconset"
|
||||
mkdir -p "$ICONSET"
|
||||
|
||||
for size in 16 32 64 128 256 512; do
|
||||
sips -z $size $size "$ICON_PNG" --out "$ICONSET/icon_${size}x${size}.png" > /dev/null 2>&1
|
||||
done
|
||||
# @2x variants
|
||||
for size in 16 32 128 256 512; do
|
||||
double=$((size * 2))
|
||||
sips -z $double $double "$ICON_PNG" --out "$ICONSET/icon_${size}x${size}@2x.png" > /dev/null 2>&1
|
||||
done
|
||||
|
||||
# Convert iconset → .icns using iconutil (built into macOS)
|
||||
iconutil -c icns "$ICONSET" -o "$ICON_DIR/AppIcon.icns" 2>/dev/null
|
||||
|
||||
# Clean up the iconset folder
|
||||
rm -rf "$ICONSET"
|
||||
|
||||
if [ -f "$ICON_DIR/AppIcon.icns" ]; then
|
||||
echo " Icon created successfully."
|
||||
else
|
||||
echo " Warning: Could not create .icns icon. The app will use a generic icon."
|
||||
fi
|
||||
else
|
||||
echo " Warning: assets/icon.png not found. The app will use a generic icon."
|
||||
fi
|
||||
|
||||
# ── Remove quarantine so macOS doesn't block it ─────────────
|
||||
xattr -d com.apple.quarantine "$APP_PATH" 2>/dev/null
|
||||
|
||||
# ── Done! ────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " Created: $APP_NAME.app"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "You can now:"
|
||||
echo " 1. Double-click it to launch the app"
|
||||
echo " 2. Drag it to your Dock for quick access"
|
||||
echo " 3. Move it to /Applications if you prefer"
|
||||
echo ""
|
||||
echo "If you move it outside this folder, it will"
|
||||
echo "ask you to locate the project folder once."
|
||||
echo ""
|
||||
echo "Done!"
|
||||
echo ""
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
DATA_DIR="/data"
|
||||
HISTORY_DIR="$DATA_DIR/history"
|
||||
CONFIG_DIR="$DATA_DIR/config"
|
||||
BIN_DIR="$DATA_DIR/bin"
|
||||
CACHE_DIR="$DATA_DIR/ytdlp-cache"
|
||||
|
||||
# Create directory structure on persistent volume
|
||||
mkdir -p "$HISTORY_DIR" "$CONFIG_DIR" "$BIN_DIR" "$CACHE_DIR"
|
||||
|
||||
# Ensure the non-root user owns the data volume
|
||||
# (on first boot the volume is root-owned; we need appuser to write)
|
||||
chown -R 1001:1001 "$DATA_DIR"
|
||||
|
||||
# Use persistent yt-dlp binary if available (runtime updates go here)
|
||||
if [ -x "$BIN_DIR/yt-dlp" ]; then
|
||||
export PATH="$BIN_DIR:$PATH"
|
||||
fi
|
||||
|
||||
# Point yt-dlp cache to persistent storage (stores OAuth tokens)
|
||||
export XDG_CACHE_HOME="$CACHE_DIR"
|
||||
|
||||
# Load Gemini API key from StartOS config if available
|
||||
if [ -f "$CONFIG_DIR/startos-config.json" ]; then
|
||||
GEMINI_KEY=$(python3 -c "import sys,json; print(json.load(open('$CONFIG_DIR/startos-config.json')).get('gemini_api_key',''))" 2>/dev/null || echo "")
|
||||
if [ -n "$GEMINI_KEY" ]; then
|
||||
export GEMINI_API_KEY="$GEMINI_KEY"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Also load from .env if it exists in data dir (user override)
|
||||
if [ -f "$DATA_DIR/.env" ]; then
|
||||
set -a
|
||||
. "$DATA_DIR/.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
export DATA_DIR="$DATA_DIR"
|
||||
export PORT="${PORT:-3001}"
|
||||
export HOSTNAME="0.0.0.0"
|
||||
|
||||
echo "Starting YouTube Summarizer..."
|
||||
echo " yt-dlp: $(yt-dlp --version 2>/dev/null || echo 'not found')"
|
||||
echo " ffmpeg: $(ffmpeg -version 2>/dev/null | head -1 || echo 'not found')"
|
||||
echo " Data: $DATA_DIR"
|
||||
|
||||
exec node /app/server/index.js
|
||||
Vendored
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"folders": [],
|
||||
"uncategorized": [
|
||||
"1775679261151-MPAsUZEJHiM",
|
||||
"1775678510294-Mv4cF13glBo",
|
||||
"1775672308695-kwSVtQ7dziU",
|
||||
"1775603102882-yLmM3M7d9v8",
|
||||
"1775599688621-Tmw2dW0a9DY",
|
||||
"1775589261845-wO5iES4qjwE",
|
||||
"1775589068370-UmLdukkI0IU",
|
||||
"1775588771329-NBu8G-5YpGI",
|
||||
"1775588353507-mjNP5IOzCbA",
|
||||
"1775587377519-Rc9lTSs7wgI",
|
||||
"1775477439435-HMTrd9Hn3e8",
|
||||
"1775430672822-lclDwnfnOGc",
|
||||
"1775430216753-Axpnkqd-Agk",
|
||||
"1775275709956-d01H-T3-frg",
|
||||
"1775274863397-N-pust8qtGI",
|
||||
"1775246692426-m3uwf5BZy1Y",
|
||||
"1775224371563-Qc6hjJ9Zze0",
|
||||
"1775224185561-C0DMdUqF73Q",
|
||||
"1775223585124-NDE0NjE5NDgtNDFi",
|
||||
"1775223278105-ovih9Xotmxg",
|
||||
"1775223130960-kjQZexuV_AE",
|
||||
"1775222710862-gwW8GKwHB3I",
|
||||
"1775222522683-lTuS7Ns8cZg",
|
||||
"1775222175607-91up0VxYeNw",
|
||||
"1775221783211-YTVSwOY19Qs",
|
||||
"1775221563723-9ZbbxSgrjhw",
|
||||
"1774302030087--JBhTBu9ZbA",
|
||||
"1774289546791-rngx_PsPxkg",
|
||||
"1773858934218--dgsZ0O-lZQ",
|
||||
"1773775610426-xaNl2EY8b-c",
|
||||
"1773695002747-hlOA8ObQJXo",
|
||||
"1773694605993-Yzg3YjFlODQtYWNl",
|
||||
"1773185576199-YThlOTAyMWYtOTU4",
|
||||
"1773021528170-MjczYmIzZjgtZjg1",
|
||||
"1772740338135-2JiMmye2ezg"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "auto-1775757891625-_5-lc6c0e2Y",
|
||||
"videoId": "_5-lc6c0e2Y",
|
||||
"url": "https://www.youtube.com/watch?v=_5-lc6c0e2Y",
|
||||
"title": "MacroVoices #527 Adam Rozencwajg & Jim Bianco: What Comes Next After The Iran Crisis",
|
||||
"uploadDate": "20260409",
|
||||
"subscriptionId": "sub-1772423650145",
|
||||
"subscriptionName": "Macro Voices",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"videoIds":["KX6q6lvoYtM","s7-l7gzm_PE","WovyQkSdONI","KKNGEr7Mc38","bzzFBvzONBo","ENW3PL50yPw","WTQwpuroPjQ","wwX0IgJYejc","RA2cvfdwy0I","dFknx-mRmKE","fenXCK0NO_w","BBKVBFrlnfw","B9udzeRK-vM","i61PKpgE3Ag","rAbJC-Qaw7Q","NEkUNahduWY","CnaegIpkenA","-ahp5X0VchM","n1E9IZfvGMA","pnn_rknhmcg","b7d71665-c736-4bc4-8072-93030cb13995","Zph8_udOKJ0","mMUNkgjwlio","mGohMkkxVj0","f2OyRTu8x3A","5mtuEf3zxTE","s0uiUWsichE","B5dZgGeXA2o","Nq3qLlcbFK0","U1oHRqUkI1E","q-sClVMYY4w","jA8ZQfq_Hzs","Gnl833wXRz0","wPy063-vd1Y","OZDFAvRq7Gc","9ZM9sCfmAGc","3hptKYix4X8","_Q4XT82yd-Q","sEXe-T-5Gn0","iDNlOGn1bTw","5kkIJNUGFho","_Fs5E5pQkLQ","X7ua58iwcd4","1aa14fcc-dd7f-45f6-bcd5-1a956b6383bb","BFt82dw0ci8","pWx_Kp6kliA","CQq3Ocm98sY","POASm17QnRk","9GzlbLIU5dU","8aUBS6z2dSI","5V-q3Sc0UIg","PSDXLvaswTI","2SNyah7nbE8","8JedAJA5AbQ","g81zFbnCZfc","NjdKMaeRBoU","m6kbpZ6JilI","mI30_ueZ7CU","jZfUANjHMF8","ie3wxnhEmYg","EVND2wqKBFE","0D8FwiFj7NM","eAKNfYJB8_c","ZZclhh9Keq8","l1qvUpHzKII","saGaeaMORA4","iCBpYwTxNiw","cf7T0TrgUUU","RUmJxQ3Hi8I","u-vMNzHgSHI","mBE_9vGJBUM","zjcYlEiwnKI","Hom5OMMzOQ0","uhpECa_XaBA","S1rQngjpUdI","9G2MRFs4vac","bdasraPo1Ak","6Uzi0OvFixw","kzWbCF_IkHY","7UeojKTzeHE","Ew0-Lg_Evj0","SaWSPZoPX34","PJh0ygZpQt8","3CZXzp1t9KE","489ca7d9-9a93-4ea4-9c0d-9ee82366f385","VPi_eWiaqdg","JsICN9ZiSjA","cru_4P6qVYQ","PF4dSKK_kww","boJRkecvyCM","xlzThNBFbk8","OnZv124nZqY","idb2PIVLLMs","4e58baFX6Go","XTnYVh7K6xQ","7RHwE_M68BY","rPaWW0IDurI","gaQwwT8Gjx0","vFTEUwYha0A","k8ZpHslhM_c","msygul3QpfU","HiVej9_fvl8","iuPQmw4Ax00","v5T1Q_5C_1w","hTY0ffRlmBQ","el6ObB60Fb4","frhd5xHQ_5Y","AVEZBy1uAk8","dnAMN9Kn8zI","ZJEnQOsMtsU","2wdsNwPUCgQ","6ctOnY1WmBw","MIKej1HCRW0","R8YC8OCnDxM","Httl6Xtf1eQ","G8Tp-3gKvu8","lxiXJKzbcp8","hPPq7NBAOvQ","yAHfG6jU2qA","zy8tpiJCEwk","3KsjuNcxTYA","u4VTFb4awrQ","elhGYEiZ7fw","gzwRflcLPAA","j95uk2BMkug","StQktHtUDbE","3bJHVYa4yMM","DMv1WLvLmQc","kC1NtDZPHuk","9y7TTU1jIvk","RAEW2KlyTy4","3ZVqcW6Wwmg","zA6gyFnlFWc","LioKxZatex0","QPkfVhYlxhE","YG7yFsXctv0","5klhxOKZ_ag","yJUk_pVN9m8","blBlD-mrIoE","L5dPkdmquNk","37LFbhjVNy0","Qbza16Y7owk","e357d703-6660-4bbb-ba40-bb7c401db429","jN6PmHUwrF0","EhEUtqEyM-8","UweigmKvoLs","vqa9qgqhT7E","LCLzgK03CQ0","wsISKLApBbk","6-mEiwe2NhE","c4tvVKDhpiY","vn_kFxqM_gw","rQ21FHpcOnY","0VSOoMuStvg","okEujapROIw","F6i7P-ZP6CY","9FEwl31hGKk","keinLNWVQXM","hnzrPKvRBD8","bHKyg77Cbs4","rjQ1L7gjCxE","lh1ij0ScKfA","dhhVs05qidI","Wh9318EAriE","9cMci6FRdMo","SSya123u9Yk","n2Mf3OotGrQ","2LRzttI1kbI","Y60lUXB8Wd8","4Gmd5UTF4rk","f7481641-a904-4d73-830a-40571b815f7d","IMAxsLAgTSQ","dcTdmQgGLDk","Bf2FIxtiWV8","77CdVSpnUX4","nxEhzsopyxY","cUngseNueP8","xZ4I2aE8zQA","GTI2ObvXMpo"]}
|
||||
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"subscriptions": [
|
||||
{
|
||||
"id": "sub-1771016441117",
|
||||
"url": "https://www.youtube.com/@TFTC/streams",
|
||||
"name": "TFTC",
|
||||
"createdAt": "2026-02-06T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:03:16.671Z",
|
||||
"paused": false,
|
||||
"channelId": "UCtdbWsnfA08KhSUO4amVLaQ"
|
||||
},
|
||||
{
|
||||
"id": "sub-1771016769660",
|
||||
"url": "https://www.youtube.com/@MartyBentTFTC/videos",
|
||||
"name": "Marty Bent",
|
||||
"createdAt": "2026-02-08T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:03:25.378Z",
|
||||
"paused": false,
|
||||
"channelId": "UCUQcW3jxfQfEUS8kqR5pJtQ"
|
||||
},
|
||||
{
|
||||
"id": "sub-1771017860588",
|
||||
"url": "https://www.youtube.com/@thejackmallersshow/streams",
|
||||
"name": "THE JACK MALLERS SHOW",
|
||||
"createdAt": "2026-02-01T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:03:26.591Z",
|
||||
"paused": false,
|
||||
"channelId": "UC3ol9RQbQHqle_Uly6w9LfA"
|
||||
},
|
||||
{
|
||||
"id": "sub-1771020687575",
|
||||
"url": "https://www.youtube.com/@Bg2Pod/videos",
|
||||
"name": "@Bg2Pod",
|
||||
"createdAt": "2025-10-01T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:03:27.833Z",
|
||||
"paused": false,
|
||||
"channelId": "UC-yRDvpR99LUc5l7i7jLzew"
|
||||
},
|
||||
{
|
||||
"id": "sub-1771020804519",
|
||||
"url": "https://www.youtube.com/@PrestonPysh/videos",
|
||||
"name": "@PrestonPysh",
|
||||
"createdAt": "2025-10-01T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:25.611Z",
|
||||
"paused": false,
|
||||
"channelId": "UCLTdCY-fNXc1GqzIuflK-OQ"
|
||||
},
|
||||
{
|
||||
"id": "sub-1771028164809",
|
||||
"url": "https://www.youtube.com/@hubermanlab/videos",
|
||||
"name": "Andrew Huberman",
|
||||
"channelId": "UC2D2CMWXMOVWx7giW1n3LIg",
|
||||
"createdAt": "2026-02-01T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:26.755Z",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"id": "sub-1771028433890",
|
||||
"url": "https://www.youtube.com/@FindingMastery/videos",
|
||||
"name": "Finding Mastery",
|
||||
"channelId": "UCSZrR-KiOLjUPbhPoPYCxNQ",
|
||||
"createdAt": "2026-02-14T00:20:33.890Z",
|
||||
"lastChecked": "2026-04-09T19:04:35.806Z",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"id": "sub-1771030240503",
|
||||
"url": "https://www.youtube.com/@tetragrammaton_now/videos",
|
||||
"name": "Tetragrammaton with Rick Rubin",
|
||||
"type": "youtube",
|
||||
"channelId": "UC5Gat6FdyiG5ydUUHqPTAEQ",
|
||||
"createdAt": "2026-02-10T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:42.980Z",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"id": "sub-1771030543882",
|
||||
"url": "https://serve.podhome.fm/rss/c90e609a-df1e-596a-bd5e-57bcc8aad6cc",
|
||||
"name": "Citadel Dispatch",
|
||||
"type": "podcast",
|
||||
"channelId": null,
|
||||
"createdAt": "2026-02-08T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:43.388Z",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"id": "sub-1771045539000",
|
||||
"url": "https://www.youtube.com/@allin/videos",
|
||||
"name": "All-In Podcast",
|
||||
"type": "youtube",
|
||||
"channelId": "UCESLZhusAkFfsNsApnjF_Cg",
|
||||
"createdAt": "2026-02-13T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:44.606Z",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"id": "sub-1772423650145",
|
||||
"url": "https://www.youtube.com/@macrovoices7508/videos",
|
||||
"name": "Macro Voices",
|
||||
"type": "youtube",
|
||||
"channelId": "UCICRehoZjq3ZtAWgRJX118A",
|
||||
"createdAt": "2026-02-02T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:46.151Z",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"id": "sub-1772462897521",
|
||||
"url": "https://www.youtube.com/@20VC/videos",
|
||||
"name": "20VC with Harry Stebbings",
|
||||
"type": "youtube",
|
||||
"channelId": "UCf0PBRjhf0rF8fWBIxTuoWA",
|
||||
"createdAt": "2026-02-20T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:47.083Z",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"id": "sub-1773418202833",
|
||||
"url": "https://www.youtube.com/@ForwardGuidanceBW/videos",
|
||||
"name": "Forward Guidance",
|
||||
"type": "youtube",
|
||||
"channelId": "UCkrwgzhIBKccuDsi_SvZtnQ",
|
||||
"createdAt": "2026-03-06T00:00:00.000Z",
|
||||
"lastChecked": "2026-04-09T19:04:48.067Z",
|
||||
"paused": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "youtube-summarizer-startos",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "rm -rf ./javascript && ncc build startos/index.ts -o ./javascript",
|
||||
"prettier": "prettier --write startos",
|
||||
"check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@start9labs/start-sdk": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.19.0",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
}
|
||||
+3680
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
||||
# ** Plumbing. DO NOT EDIT **.
|
||||
# This file is imported by ./Makefile. Make edits there
|
||||
|
||||
PACKAGE_ID := $(shell awk -F"'" '/id:/ {print $$2}' startos/manifest/index.ts)
|
||||
INGREDIENTS := $(shell start-cli s9pk list-ingredients 2>/dev/null)
|
||||
ARCHES ?= x86 arm
|
||||
TARGETS ?= arches
|
||||
|
||||
ifdef VARIANT
|
||||
BASE_NAME := $(PACKAGE_ID)_$(VARIANT)
|
||||
else
|
||||
BASE_NAME := $(PACKAGE_ID)
|
||||
endif
|
||||
|
||||
.PHONY: all arches aarch64 x86_64 riscv64 arm arm64 x86 riscv arch/* clean install check-deps check-init package ingredients
|
||||
.DELETE_ON_ERROR:
|
||||
.SECONDARY:
|
||||
|
||||
define SUMMARY
|
||||
@manifest=$$(start-cli s9pk inspect $(1) manifest); \
|
||||
size=$$(du -h $(1) | awk '{print $$1}'); \
|
||||
title=$$(printf '%s' "$$manifest" | jq -r .title); \
|
||||
version=$$(printf '%s' "$$manifest" | jq -r .version); \
|
||||
arches=$$(printf '%s' "$$manifest" | jq -r '[.images[].arch // []] | flatten | unique | join(", ")'); \
|
||||
sdkv=$$(printf '%s' "$$manifest" | jq -r .sdkVersion); \
|
||||
gitHash=$$(printf '%s' "$$manifest" | jq -r .gitHash | sed -E 's/(.*-modified)$$/\x1b[0;31m\1\x1b[0m/'); \
|
||||
printf "\n"; \
|
||||
printf "\033[1;32m✅ Build Complete!\033[0m\n"; \
|
||||
printf "\n"; \
|
||||
printf "\033[1;37m📦 $$title\033[0m \033[36mv$$version\033[0m\n"; \
|
||||
printf "───────────────────────────────\n"; \
|
||||
printf " \033[1;36mFilename:\033[0m %s\n" "$(1)"; \
|
||||
printf " \033[1;36mSize:\033[0m %s\n" "$$size"; \
|
||||
printf " \033[1;36mArch:\033[0m %s\n" "$$arches"; \
|
||||
printf " \033[1;36mSDK:\033[0m %s\n" "$$sdkv"; \
|
||||
printf " \033[1;36mGit:\033[0m %s\n" "$$gitHash"; \
|
||||
echo ""
|
||||
endef
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
arches: $(ARCHES)
|
||||
|
||||
universal: $(BASE_NAME).s9pk
|
||||
$(call SUMMARY,$<)
|
||||
|
||||
arch/%: $(BASE_NAME)_%.s9pk
|
||||
$(call SUMMARY,$<)
|
||||
|
||||
x86 x86_64: arch/x86_64
|
||||
arm arm64 aarch64: arch/aarch64
|
||||
riscv riscv64: arch/riscv64
|
||||
|
||||
$(BASE_NAME).s9pk: $(INGREDIENTS) .git/HEAD .git/index
|
||||
@$(MAKE) --no-print-directory ingredients
|
||||
@echo " Packing '$@'..."
|
||||
start-cli s9pk pack -o $@
|
||||
|
||||
$(BASE_NAME)_%.s9pk: $(INGREDIENTS) .git/HEAD .git/index
|
||||
@$(MAKE) --no-print-directory ingredients
|
||||
@echo " Packing '$@'..."
|
||||
start-cli s9pk pack --arch=$* -o $@
|
||||
|
||||
ingredients: $(INGREDIENTS)
|
||||
@echo " Re-evaluating ingredients..."
|
||||
|
||||
install: | check-deps check-init
|
||||
@HOST=$$(awk -F'/' '/^host:/ {print $$3}' ~/.startos/config.yaml); \
|
||||
if [ -z "$$HOST" ]; then \
|
||||
echo "Error: You must define \"host: http://server-name.local\" in ~/.startos/config.yaml"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
S9PK=$$(ls -t *.s9pk 2>/dev/null | head -1); \
|
||||
if [ -z "$$S9PK" ]; then \
|
||||
echo "Error: No .s9pk file found. Run 'make' first."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
printf "\n🚀 Installing %s to %s ...\n" "$$S9PK" "$$HOST"; \
|
||||
start-cli package install -s "$$S9PK"
|
||||
|
||||
check-deps:
|
||||
@command -v start-cli >/dev/null || \
|
||||
(echo "Error: start-cli not found. Please see https://docs.start9.com/packaging/0.4.0.x/environment-setup.html" && exit 1)
|
||||
@command -v npm >/dev/null || \
|
||||
(echo "Error: npm not found. Please install Node.js and npm." && exit 1)
|
||||
|
||||
check-init:
|
||||
@if [ ! -f ~/.startos/developer.key.pem ]; then \
|
||||
echo "Initializing StartOS developer environment..."; \
|
||||
start-cli init-key; \
|
||||
fi
|
||||
|
||||
javascript/index.js: $(shell find startos -type f) tsconfig.json node_modules
|
||||
npm run build
|
||||
|
||||
node_modules: package-lock.json
|
||||
npm ci
|
||||
|
||||
package-lock.json: package.json
|
||||
npm i
|
||||
|
||||
clean:
|
||||
@echo "Cleaning up build artifacts..."
|
||||
@rm -rf $(PACKAGE_ID).s9pk $(PACKAGE_ID)_x86_64.s9pk $(PACKAGE_ID)_aarch64.s9pk $(PACKAGE_ID)_riscv64.s9pk javascript node_modules
|
||||
+2621
File diff suppressed because it is too large
Load Diff
+1
@@ -0,0 +1 @@
|
||||
../glob/dist/esm/bin.mjs
|
||||
+1
@@ -0,0 +1 @@
|
||||
../mime/cli.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../which/bin/node-which
|
||||
+1
@@ -0,0 +1 @@
|
||||
../rimraf/dist/esm/bin.mjs
|
||||
+1799
File diff suppressed because it is too large
Load Diff
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+609
@@ -0,0 +1,609 @@
|
||||
# Google Gen AI SDK for TypeScript and JavaScript
|
||||
|
||||
[](https://www.npmjs.com/package/@google/genai)
|
||||
[](https://www.npmjs.com/package/@google/genai)
|
||||
|
||||
----------------------
|
||||
**Documentation:** https://googleapis.github.io/js-genai/
|
||||
|
||||
----------------------
|
||||
|
||||
The Google Gen AI JavaScript SDK is designed for
|
||||
TypeScript and JavaScript developers to build applications powered by Gemini. The SDK
|
||||
supports both the [Gemini Developer API](https://ai.google.dev/gemini-api/docs)
|
||||
and [Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/overview).
|
||||
|
||||
The Google Gen AI SDK is designed to work with Gemini 2.0+ features.
|
||||
|
||||
> [!CAUTION]
|
||||
> **API Key Security:** Avoid exposing API keys in client-side code.
|
||||
> Use server-side implementations in production environments.
|
||||
|
||||
## Code Generation
|
||||
|
||||
Generative models are often unaware of recent API and SDK updates and may suggest outdated or legacy code.
|
||||
|
||||
We recommend using our Code Generation instructions [`codegen_instructions.md`](https://raw.githubusercontent.com/googleapis/js-genai/refs/heads/main/codegen_instructions.md) when generating Google Gen AI SDK code to guide your model towards using the more recent SDK features. Copy and paste the instructions into your development environment to provide the model with the necessary context.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Node.js version 20 or later
|
||||
|
||||
### The following are required for Vertex AI users (excluding Vertex AI Studio)
|
||||
1. [Select](https://console.cloud.google.com/project) or [create](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project) a Google Cloud project.
|
||||
1. [Enable billing for your project](https://cloud.google.com/billing/docs/how-to/modify-project).
|
||||
1. [Enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).
|
||||
1. [Configure authentication](https://cloud.google.com/docs/authentication) for your project.
|
||||
* [Install the gcloud CLI](https://cloud.google.com/sdk/docs/install).
|
||||
* [Initialize the gcloud CLI](https://cloud.google.com/sdk/docs/initializing).
|
||||
* Create local authentication credentials for your user account:
|
||||
|
||||
```sh
|
||||
gcloud auth application-default login
|
||||
```
|
||||
A list of accepted authentication options are listed in [GoogleAuthOptions](https://github.com/googleapis/google-auth-library-nodejs/blob/3ae120d0a45c95e36c59c9ac8286483938781f30/src/auth/googleauth.ts#L87) interface of google-auth-library-node.js GitHub repo.
|
||||
|
||||
## Installation
|
||||
|
||||
To install the SDK, run the following command:
|
||||
|
||||
```shell
|
||||
npm install @google/genai
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
The simplest way to get started is to use an API key from
|
||||
[Google AI Studio](https://aistudio.google.com/apikey):
|
||||
|
||||
```typescript
|
||||
import {GoogleGenAI} from '@google/genai';
|
||||
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
||||
|
||||
const ai = new GoogleGenAI({apiKey: GEMINI_API_KEY});
|
||||
|
||||
async function main() {
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'Why is the sky blue?',
|
||||
});
|
||||
console.log(response.text);
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
## Initialization
|
||||
|
||||
The Google Gen AI SDK provides support for both the
|
||||
[Google AI Studio](https://ai.google.dev/gemini-api/docs) and
|
||||
[Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/overview)
|
||||
implementations of the Gemini API.
|
||||
|
||||
### Gemini Developer API
|
||||
|
||||
For server-side applications, initialize using an API key, which can
|
||||
be acquired from [Google AI Studio](https://aistudio.google.com/apikey):
|
||||
|
||||
```typescript
|
||||
import { GoogleGenAI } from '@google/genai';
|
||||
const ai = new GoogleGenAI({apiKey: 'GEMINI_API_KEY'});
|
||||
```
|
||||
|
||||
#### Browser
|
||||
|
||||
> [!CAUTION]
|
||||
> **API Key Security:** Avoid exposing API keys in client-side code.
|
||||
> Use server-side implementations in production environments.
|
||||
|
||||
In the browser the initialization code is identical:
|
||||
|
||||
|
||||
```typescript
|
||||
import { GoogleGenAI } from '@google/genai';
|
||||
const ai = new GoogleGenAI({apiKey: 'GEMINI_API_KEY'});
|
||||
```
|
||||
|
||||
### Vertex AI
|
||||
|
||||
Sample code for VertexAI initialization:
|
||||
|
||||
```typescript
|
||||
import { GoogleGenAI } from '@google/genai';
|
||||
|
||||
const ai = new GoogleGenAI({
|
||||
vertexai: true,
|
||||
project: 'your_project',
|
||||
location: 'your_location',
|
||||
});
|
||||
```
|
||||
|
||||
### (Optional) (NodeJS only) Using environment variables:
|
||||
|
||||
For NodeJS environments, you can create a client by configuring the necessary
|
||||
environment variables. Configuration setup instructions depends on whether
|
||||
you're using the Gemini Developer API or the Gemini API in Vertex AI.
|
||||
|
||||
**Gemini Developer API:** Set `GOOGLE_API_KEY` as shown below:
|
||||
|
||||
```bash
|
||||
export GOOGLE_API_KEY='your-api-key'
|
||||
```
|
||||
|
||||
**Gemini API on Vertex AI:** Set `GOOGLE_GENAI_USE_VERTEXAI`,
|
||||
`GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION`, as shown below:
|
||||
|
||||
```bash
|
||||
export GOOGLE_GENAI_USE_VERTEXAI=true
|
||||
export GOOGLE_CLOUD_PROJECT='your-project-id'
|
||||
export GOOGLE_CLOUD_LOCATION='us-central1'
|
||||
```
|
||||
|
||||
```typescript
|
||||
import {GoogleGenAI} from '@google/genai';
|
||||
|
||||
const ai = new GoogleGenAI();
|
||||
```
|
||||
|
||||
## API Selection
|
||||
|
||||
By default, the SDK uses the beta API endpoints provided by Google to support
|
||||
preview features in the APIs. The stable API endpoints can be selected by
|
||||
setting the API version to `v1`.
|
||||
|
||||
To set the API version use `apiVersion`. For example, to set the API version to
|
||||
`v1` for Vertex AI:
|
||||
|
||||
```typescript
|
||||
const ai = new GoogleGenAI({
|
||||
vertexai: true,
|
||||
project: 'your_project',
|
||||
location: 'your_location',
|
||||
apiVersion: 'v1'
|
||||
});
|
||||
```
|
||||
|
||||
To set the API version to `v1alpha` for the Gemini Developer API:
|
||||
|
||||
```typescript
|
||||
const ai = new GoogleGenAI({
|
||||
apiKey: 'GEMINI_API_KEY',
|
||||
apiVersion: 'v1alpha'
|
||||
});
|
||||
```
|
||||
|
||||
## GoogleGenAI overview
|
||||
|
||||
All API features are accessed through an instance of the `GoogleGenAI` classes.
|
||||
The submodules bundle together related API methods:
|
||||
|
||||
- [`ai.models`](https://googleapis.github.io/js-genai/release_docs/classes/models.Models.html):
|
||||
Use `models` to query models (`generateContent`, `generateImages`, ...), or
|
||||
examine their metadata.
|
||||
- [`ai.caches`](https://googleapis.github.io/js-genai/release_docs/classes/caches.Caches.html):
|
||||
Create and manage `caches` to reduce costs when repeatedly using the same
|
||||
large prompt prefix.
|
||||
- [`ai.chats`](https://googleapis.github.io/js-genai/release_docs/classes/chats.Chats.html):
|
||||
Create local stateful `chat` objects to simplify multi turn interactions.
|
||||
- [`ai.files`](https://googleapis.github.io/js-genai/release_docs/classes/files.Files.html):
|
||||
Upload `files` to the API and reference them in your prompts.
|
||||
This reduces bandwidth if you use a file many times, and handles files too
|
||||
large to fit inline with your prompt.
|
||||
- [`ai.live`](https://googleapis.github.io/js-genai/release_docs/classes/live.Live.html):
|
||||
Start a `live` session for real time interaction, allows text + audio + video
|
||||
input, and text or audio output.
|
||||
|
||||
## Samples
|
||||
|
||||
More samples can be found in the
|
||||
[github samples directory](https://github.com/googleapis/js-genai/tree/main/sdk-samples).
|
||||
|
||||
### Streaming
|
||||
|
||||
For quicker, more responsive API interactions use the `generateContentStream`
|
||||
method which yields chunks as they're generated:
|
||||
|
||||
```typescript
|
||||
import {GoogleGenAI} from '@google/genai';
|
||||
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
||||
|
||||
const ai = new GoogleGenAI({apiKey: GEMINI_API_KEY});
|
||||
|
||||
async function main() {
|
||||
const response = await ai.models.generateContentStream({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'Write a 100-word poem.',
|
||||
});
|
||||
for await (const chunk of response) {
|
||||
console.log(chunk.text);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
### Function Calling
|
||||
|
||||
To let Gemini to interact with external systems, you can provide
|
||||
`functionDeclaration` objects as `tools`. To use these tools it's a 4 step
|
||||
|
||||
1. **Declare the function name, description, and parametersJsonSchema**
|
||||
2. **Call `generateContent` with function calling enabled**
|
||||
3. **Use the returned `FunctionCall` parameters to call your actual function**
|
||||
3. **Send the result back to the model (with history, easier in `ai.chat`)
|
||||
as a `FunctionResponse`**
|
||||
|
||||
```typescript
|
||||
import {GoogleGenAI, FunctionCallingConfigMode, FunctionDeclaration, Type} from '@google/genai';
|
||||
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
||||
|
||||
async function main() {
|
||||
const controlLightDeclaration: FunctionDeclaration = {
|
||||
name: 'controlLight',
|
||||
parametersJsonSchema: {
|
||||
type: 'object',
|
||||
properties:{
|
||||
brightness: {
|
||||
type:'number',
|
||||
},
|
||||
colorTemperature: {
|
||||
type:'string',
|
||||
},
|
||||
},
|
||||
required: ['brightness', 'colorTemperature'],
|
||||
},
|
||||
};
|
||||
|
||||
const ai = new GoogleGenAI({apiKey: GEMINI_API_KEY});
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'Dim the lights so the room feels cozy and warm.',
|
||||
config: {
|
||||
toolConfig: {
|
||||
functionCallingConfig: {
|
||||
// Force it to call any function
|
||||
mode: FunctionCallingConfigMode.ANY,
|
||||
allowedFunctionNames: ['controlLight'],
|
||||
}
|
||||
},
|
||||
tools: [{functionDeclarations: [controlLightDeclaration]}]
|
||||
}
|
||||
});
|
||||
|
||||
console.log(response.functionCalls);
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
#### Model Context Protocol (MCP) support (experimental)
|
||||
|
||||
Built-in [MCP](https://modelcontextprotocol.io/introduction) support is an
|
||||
experimental feature. You can pass a local MCP server as a tool directly.
|
||||
|
||||
```javascript
|
||||
import { GoogleGenAI, FunctionCallingConfigMode , mcpToTool} from '@google/genai';
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
||||
|
||||
// Create server parameters for stdio connection
|
||||
const serverParams = new StdioClientTransport({
|
||||
command: "npx", // Executable
|
||||
args: ["-y", "@philschmid/weather-mcp"] // MCP Server
|
||||
});
|
||||
|
||||
const client = new Client(
|
||||
{
|
||||
name: "example-client",
|
||||
version: "1.0.0"
|
||||
}
|
||||
);
|
||||
|
||||
// Configure the client
|
||||
const ai = new GoogleGenAI({});
|
||||
|
||||
// Initialize the connection between client and server
|
||||
await client.connect(serverParams);
|
||||
|
||||
// Send request to the model with MCP tools
|
||||
const response = await ai.models.generateContent({
|
||||
model: "gemini-2.5-flash",
|
||||
contents: `What is the weather in London in ${new Date().toLocaleDateString()}?`,
|
||||
config: {
|
||||
tools: [mcpToTool(client)], // uses the session, will automatically call the tool using automatic function calling
|
||||
},
|
||||
});
|
||||
console.log(response.text);
|
||||
|
||||
// Close the connection
|
||||
await client.close();
|
||||
```
|
||||
|
||||
### Generate Content
|
||||
|
||||
#### How to structure `contents` argument for `generateContent`
|
||||
|
||||
The SDK allows you to specify the following types in the `contents` parameter:
|
||||
|
||||
#### Content
|
||||
|
||||
- `Content`: The SDK will wrap the singular `Content` instance in an array which
|
||||
contains only the given content instance
|
||||
- `Content[]`: No transformation happens
|
||||
|
||||
#### Part
|
||||
|
||||
Parts will be aggregated on a singular Content, with role 'user'.
|
||||
|
||||
- `Part | string`: The SDK will wrap the `string` or `Part` in a `Content`
|
||||
instance with role 'user'.
|
||||
- `Part[] | string[]`: The SDK will wrap the full provided list into a single
|
||||
`Content` with role 'user'.
|
||||
|
||||
**_NOTE:_** This doesn't apply to `FunctionCall` and `FunctionResponse` parts,
|
||||
if you are specifying those, you need to explicitly provide the full
|
||||
`Content[]` structure making it explicit which Parts are 'spoken' by the model,
|
||||
or the user. The SDK will throw an exception if you try this.
|
||||
|
||||
## Error Handling
|
||||
|
||||
To handle errors raised by the API, the SDK provides this [ApiError](https://github.com/googleapis/js-genai/blob/main/src/errors.ts) class.
|
||||
|
||||
```typescript
|
||||
import {GoogleGenAI} from '@google/genai';
|
||||
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
||||
|
||||
const ai = new GoogleGenAI({apiKey: GEMINI_API_KEY});
|
||||
|
||||
async function main() {
|
||||
await ai.models.generateContent({
|
||||
model: 'non-existent-model',
|
||||
contents: 'Write a 100-word poem.',
|
||||
}).catch((e) => {
|
||||
console.error('error name: ', e.name);
|
||||
console.error('error message: ', e.message);
|
||||
console.error('error status: ', e.status);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
## Interactions (Preview)
|
||||
|
||||
> **Warning:** The Interactions API is in **Beta**. This is a preview of an
|
||||
experimental feature. Features and schemas are subject to **breaking changes**.
|
||||
|
||||
The Interactions API is a unified interface for interacting with Gemini models
|
||||
and agents. It simplifies state management, tool orchestration, and long-running
|
||||
tasks.
|
||||
|
||||
See the [documentation site](https://ai.google.dev/gemini-api/docs/interactions)
|
||||
for more details.
|
||||
|
||||
### Basic Interaction
|
||||
|
||||
```typescript
|
||||
const interaction = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
input: 'Hello, how are you?',
|
||||
});
|
||||
console.debug(interaction);
|
||||
|
||||
```
|
||||
|
||||
### Stateful Conversation
|
||||
|
||||
The Interactions API supports server-side state management. You can continue a
|
||||
conversation by referencing the `previous_interaction_id`.
|
||||
|
||||
```typescript
|
||||
// 1. First turn
|
||||
const interaction1 = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
input: 'Hi, my name is Amir.',
|
||||
});
|
||||
console.debug(interaction1);
|
||||
|
||||
// 2. Second turn (passing previous_interaction_id)
|
||||
const interaction2 = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
input: 'What is my name?',
|
||||
previous_interaction_id: interaction1.id,
|
||||
});
|
||||
console.debug(interaction2);
|
||||
|
||||
```
|
||||
|
||||
### Agents (Deep Research)
|
||||
|
||||
You can use specialized agents like `deep-research-pro-preview-12-2025` for
|
||||
complex tasks.
|
||||
|
||||
```typescript
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// 1. Start the Deep Research Agent
|
||||
const initialInteraction = await ai.interactions.create({
|
||||
input:
|
||||
'Research the history of the Google TPUs with a focus on 2025 and 2026.',
|
||||
agent: 'deep-research-pro-preview-12-2025',
|
||||
background: true,
|
||||
});
|
||||
|
||||
console.log(`Research started. Interaction ID: ${initialInteraction.id}`);
|
||||
|
||||
// 2. Poll for results
|
||||
while (true) {
|
||||
const interaction = await ai.interactions.get(initialInteraction.id);
|
||||
console.log(`Status: ${interaction.status}`);
|
||||
|
||||
if (interaction.status === 'completed') {
|
||||
console.debug('\nFinal Report:\n', interaction.outputs);
|
||||
break;
|
||||
} else if (['failed', 'cancelled'].includes(interaction.status)) {
|
||||
console.log(`Failed with status: ${interaction.status}`);
|
||||
break;
|
||||
}
|
||||
|
||||
await sleep(10000); // Sleep for 10 seconds
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Multimodal Input
|
||||
|
||||
You can provide multimodal data (text, images, audio, etc.) in the input list.
|
||||
|
||||
```typescript
|
||||
import base64
|
||||
|
||||
// Assuming you have a base64 string
|
||||
// const base64Image = ...;
|
||||
|
||||
const interaction = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
input: [
|
||||
{ type: 'text', text: 'Describe the image.' },
|
||||
{ type: 'image', data: base64Image, mime_type: 'image/png' },
|
||||
],
|
||||
});
|
||||
|
||||
console.debug(interaction);
|
||||
|
||||
```
|
||||
|
||||
### Function Calling
|
||||
|
||||
You can define custom functions for the model to use. The Interactions API
|
||||
handles the tool selection, and you provide the execution result back to the
|
||||
model.
|
||||
|
||||
```typescript
|
||||
// 1. Define the tool
|
||||
const getWeather = (location: string) => {
|
||||
/* Gets the weather for a given location. */
|
||||
return `The weather in ${location} is sunny.`;
|
||||
};
|
||||
|
||||
// 2. Send the request with tools
|
||||
let interaction = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
input: 'What is the weather in Mountain View, CA?',
|
||||
tools: [
|
||||
{
|
||||
type: 'function',
|
||||
name: 'get_weather',
|
||||
description: 'Gets the weather for a given location.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
location: {
|
||||
type: 'string',
|
||||
description: 'The city and state, e.g. San Francisco, CA',
|
||||
},
|
||||
},
|
||||
required: ['location'],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 3. Handle the tool call
|
||||
for (const output of interaction.outputs!) {
|
||||
if (output.type === 'function_call') {
|
||||
console.log(
|
||||
`Tool Call: ${output.name}(${JSON.stringify(output.arguments)})`);
|
||||
|
||||
// Execute your actual function here
|
||||
// Note: ensure arguments match your function signature
|
||||
const result = getWeather(JSON.stringify(output.arguments.location));
|
||||
|
||||
// Send result back to the model
|
||||
interaction = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
previous_interaction_id: interaction.id,
|
||||
input: [
|
||||
{
|
||||
type: 'function_result',
|
||||
name: output.name,
|
||||
call_id: output.id,
|
||||
result: result,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
console.debug(`Response: ${JSON.stringify(interaction)}`);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Built-in Tools
|
||||
You can also use Google's built-in tools, such as **Google Search** or **Code
|
||||
Execution**.
|
||||
|
||||
#### Grounding with Google Search
|
||||
|
||||
```typescript
|
||||
const interaction = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
input: 'Who won the last Super Bowl',
|
||||
tools: [{ type: 'google_search' }],
|
||||
});
|
||||
|
||||
console.debug(interaction);
|
||||
|
||||
```
|
||||
|
||||
#### Code Execution
|
||||
|
||||
```typescript
|
||||
const interaction = await ai.interactions.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
input: 'Calculate the 50th Fibonacci number.',
|
||||
tools: [{ type: 'code_execution' }],
|
||||
});
|
||||
|
||||
console.debug(interaction);
|
||||
|
||||
```
|
||||
|
||||
### Multimodal Output
|
||||
|
||||
The Interactions API can generate multimodal outputs, such as images. You must
|
||||
specify the `response_modalities`.
|
||||
|
||||
```typescript
|
||||
import * as fs from 'fs';
|
||||
|
||||
const interaction = await ai.interactions.create({
|
||||
model: 'gemini-3-pro-image-preview',
|
||||
input: 'Generate an image of a futuristic city.',
|
||||
response_modalities: ['image'],
|
||||
});
|
||||
|
||||
for (const output of interaction.outputs!) {
|
||||
if (output.type === 'image') {
|
||||
console.log(`Generated image with mime_type: ${output.mime_type}`);
|
||||
// Save the image
|
||||
fs.writeFileSync(
|
||||
'generated_city.png', Buffer.from(output.data!, 'base64'));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## How is this different from the other Google AI SDKs
|
||||
This SDK (`@google/genai`) is Google Deepmind’s "vanilla" SDK for its generative
|
||||
AI offerings, and is where Google Deepmind adds new AI features.
|
||||
|
||||
Models hosted either on the [Vertex AI platform](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/overview) or the [Gemini Developer platform](https://ai.google.dev/gemini-api/docs) are accessible through this SDK.
|
||||
|
||||
Other SDKs may be offering additional AI frameworks on top of this SDK, or may
|
||||
be targeting specific project environments (like Firebase).
|
||||
|
||||
The `@google/generative_language` and `@google-cloud/vertexai` SDKs are previous
|
||||
iterations of this SDK and are no longer receiving new Gemini 2.0+ features.
|
||||
+11244
File diff suppressed because it is too large
Load Diff
+19595
File diff suppressed because it is too large
Load Diff
+19518
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+20083
File diff suppressed because it is too large
Load Diff
+19986
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+11256
File diff suppressed because it is too large
Load Diff
+5680
File diff suppressed because it is too large
Load Diff
+1168
File diff suppressed because it is too large
Load Diff
+5656
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+19573
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+11249
File diff suppressed because it is too large
Load Diff
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@google/genai/node",
|
||||
"main": "../dist/node/index.js"
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
{
|
||||
"name": "@google/genai",
|
||||
"version": "1.41.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"main": "dist/node/index.mjs",
|
||||
"module": "dist/web/index.mjs",
|
||||
"browser": "dist/web/index.mjs",
|
||||
"typings": "dist/genai.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"browser": {
|
||||
"types": "./dist/web/web.d.ts",
|
||||
"import": "./dist/web/index.mjs",
|
||||
"default": "./dist/web/index.mjs"
|
||||
},
|
||||
"node": {
|
||||
"types": "./dist/node/node.d.ts",
|
||||
"import": "./dist/node/index.mjs",
|
||||
"require": "./dist/node/index.cjs",
|
||||
"default": "./dist/node/index.mjs"
|
||||
},
|
||||
"types": "./dist/genai.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs",
|
||||
"default": "./dist/index.mjs"
|
||||
},
|
||||
"./web": {
|
||||
"types": "./dist/web/web.d.ts",
|
||||
"import": "./dist/web/index.mjs",
|
||||
"default": "./dist/web/index.mjs"
|
||||
},
|
||||
"./node": {
|
||||
"types": "./dist/node/node.d.ts",
|
||||
"import": "./dist/node/index.mjs",
|
||||
"default": "./dist/node/index.mjs"
|
||||
},
|
||||
"./tokenizer": {
|
||||
"node": {
|
||||
"types": "./dist/tokenizer/node.d.ts",
|
||||
"import": "./dist/tokenizer/node.mjs",
|
||||
"require": "./dist/tokenizer/node.cjs",
|
||||
"default": "./dist/tokenizer/node.mjs"
|
||||
},
|
||||
"types": "./dist/tokenizer/node.d.ts",
|
||||
"import": "./dist/tokenizer/node.mjs",
|
||||
"require": "./dist/tokenizer/node.cjs",
|
||||
"default": "./dist/tokenizer/node.mjs"
|
||||
},
|
||||
"./tokenizer/node": {
|
||||
"types": "./dist/tokenizer/node.d.ts",
|
||||
"import": "./dist/tokenizer/node.mjs",
|
||||
"require": "./dist/tokenizer/node.cjs",
|
||||
"default": "./dist/tokenizer/node.mjs"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "node scripts/prepare.js",
|
||||
"build": "patch-package && rollup -c && npm-run-all --parallel api-extractor:dev:* && node scripts/ignore_missing_mcp_dep.js",
|
||||
"build-prod": "patch-package && rollup -c && npm-run-all --parallel api-extractor:prod:* && node scripts/ignore_missing_mcp_dep.js",
|
||||
"api-extractor:dev:main": "api-extractor run --local --verbose",
|
||||
"api-extractor:dev:node": "api-extractor run -c api-extractor.node.json --local --verbose",
|
||||
"api-extractor:dev:web": "api-extractor run -c api-extractor.web.json --local --verbose",
|
||||
"api-extractor:dev:tokenizer-node": "api-extractor run -c api-extractor.tokenizer-node.json --local --verbose",
|
||||
"api-extractor:prod:main": "api-extractor run --verbose",
|
||||
"api-extractor:prod:node": "api-extractor run -c api-extractor.node.json --verbose",
|
||||
"api-extractor:prod:web": "api-extractor run -c api-extractor.web.json --verbose",
|
||||
"api-extractor:prod:tokenizer-node": "api-extractor run -c api-extractor.tokenizer-node.json --verbose",
|
||||
"unit-test": "tsc && cp src/cross/sentencepiece/sentencepiece_model.pb.js dist/src/cross/sentencepiece/ && jasmine dist/test/unit/**/*_test.js dist/test/unit/**/**/*_test.js dist/test/unit/*_test.js",
|
||||
"system-test": "tsc && jasmine dist/test/system/**/*_test.js",
|
||||
"test-server-tests": "tsc && GOOGLE_CLOUD_PROJECT=googcloudproj GOOGLE_CLOUD_LOCATION=googcloudloc jasmine dist/test/system/node/*_test.js -- --test-server",
|
||||
"test-server-tests:record": "tsc && jasmine --fail-fast dist/test/system/node/*_test.js -- --test-server --record",
|
||||
"docs": "typedoc && node --loader ts-node/esm scripts/add_docsite_license_headers.ts",
|
||||
"pages-main": "node --loader ts-node/esm scripts/generate_pages.ts main",
|
||||
"pages-release": "node --loader ts-node/esm scripts/generate_pages.ts release",
|
||||
"format": "prettier '**/*.ts' '**/*.mjs' '**/*.json' --write",
|
||||
"lint": "eslint '**/*.ts'",
|
||||
"lint-fix": "eslint --fix '**/*.ts'",
|
||||
"coverage-report": "./test/generate_report.sh",
|
||||
"generate-proto": "pbjs -t static-module -w es6 -o src/cross/sentencepiece/sentencepiece_model.pb.js src/cross/sentencepiece/sentencepiece_model.proto && pbts -o src/cross/sentencepiece/sentencepiece_model.pb.d.ts src/cross/sentencepiece/sentencepiece_model.pb.js && sed -i.bak 's/import \\* as \\$protobuf from \"protobufjs\\/minimal\"/import \\$protobuf from \"protobufjs\\/minimal.js\"/' src/cross/sentencepiece/sentencepiece_model.pb.js && rm src/cross/sentencepiece/sentencepiece_model.pb.js.bak"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"overrides": {
|
||||
"tmp": "^0.2.4"
|
||||
},
|
||||
"files": [
|
||||
"dist/genai.d.ts",
|
||||
"dist/index.mjs",
|
||||
"dist/index.cjs",
|
||||
"dist/index.mjs.map",
|
||||
"dist/node/index.mjs",
|
||||
"dist/node/index.cjs",
|
||||
"dist/node/index.mjs.map",
|
||||
"dist/node/node.d.ts",
|
||||
"dist/web/index.mjs",
|
||||
"dist/web/index.mjs.map",
|
||||
"dist/web/web.d.ts",
|
||||
"dist/tokenizer/node.mjs",
|
||||
"dist/tokenizer/node.cjs",
|
||||
"dist/tokenizer/node.mjs.map",
|
||||
"dist/tokenizer/node.d.ts",
|
||||
"node/package.json",
|
||||
"web/package.json"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@cfworker/json-schema": "^4.1.1",
|
||||
"@eslint/js": "9.20.0",
|
||||
"@microsoft/api-extractor": "^7.52.9",
|
||||
"@modelcontextprotocol/sdk": "^1.25.2",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@types/jasmine": "^5.1.2",
|
||||
"@types/node": "^20.9.0",
|
||||
"@types/node-fetch": "^2.6.13",
|
||||
"@types/unist": "^3.0.3",
|
||||
"@types/ws": "^8.5.14",
|
||||
"c8": "^10.1.3",
|
||||
"eslint": "8.57.0",
|
||||
"gts": "^5.2.0",
|
||||
"jasmine": "^5.5.0",
|
||||
"jasmine-reporters": "^2.4.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"nyc": "^17.1.0",
|
||||
"patch-package": "^8.0.1",
|
||||
"prettier": "3.3.3",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"protobufjs-cli": "^1.1.3",
|
||||
"rollup-plugin-typescript2": "^0.36.0",
|
||||
"test-server-sdk": "^0.2.9",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
"tsx": "^4.19.4",
|
||||
"typedoc": "^0.27.0",
|
||||
"typescript": "~5.4.0",
|
||||
"typescript-eslint": "8.24.1",
|
||||
"undici": "^7.16.0",
|
||||
"undici-types": "^7.16.0",
|
||||
"zod": "^3.25.0",
|
||||
"zod-to-json-schema": "^3.25.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"google-auth-library": "^10.3.0",
|
||||
"p-retry": "^7.1.1",
|
||||
"protobufjs": "^7.5.4",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.25.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@modelcontextprotocol/sdk": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/googleapis/js-genai.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/googleapis/js-genai/issues"
|
||||
},
|
||||
"homepage": "https://github.com/googleapis/js-genai#readme",
|
||||
"author": "",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@google/genai/web",
|
||||
"module": "../dist/web/index.mjs"
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
Copyright (c) 2015, Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice
|
||||
appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
# @isaacs/cliui
|
||||
|
||||
Temporary fork of [cliui](http://npm.im/cliui).
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/cliui)
|
||||
[](https://conventionalcommits.org)
|
||||

|
||||
|
||||
easily create complex multi-column command-line-interfaces.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const ui = require('cliui')()
|
||||
|
||||
ui.div('Usage: $0 [command] [options]')
|
||||
|
||||
ui.div({
|
||||
text: 'Options:',
|
||||
padding: [2, 0, 1, 0]
|
||||
})
|
||||
|
||||
ui.div(
|
||||
{
|
||||
text: "-f, --file",
|
||||
width: 20,
|
||||
padding: [0, 4, 0, 4]
|
||||
},
|
||||
{
|
||||
text: "the file to load." +
|
||||
chalk.green("(if this description is long it wraps).")
|
||||
,
|
||||
width: 20
|
||||
},
|
||||
{
|
||||
text: chalk.red("[required]"),
|
||||
align: 'right'
|
||||
}
|
||||
)
|
||||
|
||||
console.log(ui.toString())
|
||||
```
|
||||
|
||||
## Deno/ESM Support
|
||||
|
||||
As of `v7` `cliui` supports [Deno](https://github.com/denoland/deno) and
|
||||
[ESM](https://nodejs.org/api/esm.html#esm_ecmascript_modules):
|
||||
|
||||
```typescript
|
||||
import cliui from "https://deno.land/x/cliui/deno.ts";
|
||||
|
||||
const ui = cliui({})
|
||||
|
||||
ui.div('Usage: $0 [command] [options]')
|
||||
|
||||
ui.div({
|
||||
text: 'Options:',
|
||||
padding: [2, 0, 1, 0]
|
||||
})
|
||||
|
||||
ui.div({
|
||||
text: "-f, --file",
|
||||
width: 20,
|
||||
padding: [0, 4, 0, 4]
|
||||
})
|
||||
|
||||
console.log(ui.toString())
|
||||
```
|
||||
|
||||
<img width="500" src="screenshot.png">
|
||||
|
||||
## Layout DSL
|
||||
|
||||
cliui exposes a simple layout DSL:
|
||||
|
||||
If you create a single `ui.div`, passing a string rather than an
|
||||
object:
|
||||
|
||||
* `\n`: characters will be interpreted as new rows.
|
||||
* `\t`: characters will be interpreted as new columns.
|
||||
* `\s`: characters will be interpreted as padding.
|
||||
|
||||
**as an example...**
|
||||
|
||||
```js
|
||||
var ui = require('./')({
|
||||
width: 60
|
||||
})
|
||||
|
||||
ui.div(
|
||||
'Usage: node ./bin/foo.js\n' +
|
||||
' <regex>\t provide a regex\n' +
|
||||
' <glob>\t provide a glob\t [required]'
|
||||
)
|
||||
|
||||
console.log(ui.toString())
|
||||
```
|
||||
|
||||
**will output:**
|
||||
|
||||
```shell
|
||||
Usage: node ./bin/foo.js
|
||||
<regex> provide a regex
|
||||
<glob> provide a glob [required]
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
```js
|
||||
cliui = require('cliui')
|
||||
```
|
||||
|
||||
### cliui({width: integer})
|
||||
|
||||
Specify the maximum width of the UI being generated.
|
||||
If no width is provided, cliui will try to get the current window's width and use it, and if that doesn't work, width will be set to `80`.
|
||||
|
||||
### cliui({wrap: boolean})
|
||||
|
||||
Enable or disable the wrapping of text in a column.
|
||||
|
||||
### cliui.div(column, column, column)
|
||||
|
||||
Create a row with any number of columns, a column
|
||||
can either be a string, or an object with the following
|
||||
options:
|
||||
|
||||
* **text:** some text to place in the column.
|
||||
* **width:** the width of a column.
|
||||
* **align:** alignment, `right` or `center`.
|
||||
* **padding:** `[top, right, bottom, left]`.
|
||||
* **border:** should a border be placed around the div?
|
||||
|
||||
### cliui.span(column, column, column)
|
||||
|
||||
Similar to `div`, except the next row will be appended without
|
||||
a new line being created.
|
||||
|
||||
### cliui.resetOutput()
|
||||
|
||||
Resets the UI elements of the current cliui instance, maintaining the values
|
||||
set for `width` and `wrap`.
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
'use strict';
|
||||
|
||||
const align = {
|
||||
right: alignRight,
|
||||
center: alignCenter
|
||||
};
|
||||
const top = 0;
|
||||
const right = 1;
|
||||
const bottom = 2;
|
||||
const left = 3;
|
||||
class UI {
|
||||
constructor(opts) {
|
||||
var _a;
|
||||
this.width = opts.width;
|
||||
/* c8 ignore start */
|
||||
this.wrap = (_a = opts.wrap) !== null && _a !== void 0 ? _a : true;
|
||||
/* c8 ignore stop */
|
||||
this.rows = [];
|
||||
}
|
||||
span(...args) {
|
||||
const cols = this.div(...args);
|
||||
cols.span = true;
|
||||
}
|
||||
resetOutput() {
|
||||
this.rows = [];
|
||||
}
|
||||
div(...args) {
|
||||
if (args.length === 0) {
|
||||
this.div('');
|
||||
}
|
||||
if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') {
|
||||
return this.applyLayoutDSL(args[0]);
|
||||
}
|
||||
const cols = args.map(arg => {
|
||||
if (typeof arg === 'string') {
|
||||
return this.colFromString(arg);
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
this.rows.push(cols);
|
||||
return cols;
|
||||
}
|
||||
shouldApplyLayoutDSL(...args) {
|
||||
return args.length === 1 && typeof args[0] === 'string' &&
|
||||
/[\t\n]/.test(args[0]);
|
||||
}
|
||||
applyLayoutDSL(str) {
|
||||
const rows = str.split('\n').map(row => row.split('\t'));
|
||||
let leftColumnWidth = 0;
|
||||
// simple heuristic for layout, make sure the
|
||||
// second column lines up along the left-hand.
|
||||
// don't allow the first column to take up more
|
||||
// than 50% of the screen.
|
||||
rows.forEach(columns => {
|
||||
if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) {
|
||||
leftColumnWidth = Math.min(Math.floor(this.width * 0.5), mixin.stringWidth(columns[0]));
|
||||
}
|
||||
});
|
||||
// generate a table:
|
||||
// replacing ' ' with padding calculations.
|
||||
// using the algorithmically generated width.
|
||||
rows.forEach(columns => {
|
||||
this.div(...columns.map((r, i) => {
|
||||
return {
|
||||
text: r.trim(),
|
||||
padding: this.measurePadding(r),
|
||||
width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
|
||||
};
|
||||
}));
|
||||
});
|
||||
return this.rows[this.rows.length - 1];
|
||||
}
|
||||
colFromString(text) {
|
||||
return {
|
||||
text,
|
||||
padding: this.measurePadding(text)
|
||||
};
|
||||
}
|
||||
measurePadding(str) {
|
||||
// measure padding without ansi escape codes
|
||||
const noAnsi = mixin.stripAnsi(str);
|
||||
return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length];
|
||||
}
|
||||
toString() {
|
||||
const lines = [];
|
||||
this.rows.forEach(row => {
|
||||
this.rowToString(row, lines);
|
||||
});
|
||||
// don't display any lines with the
|
||||
// hidden flag set.
|
||||
return lines
|
||||
.filter(line => !line.hidden)
|
||||
.map(line => line.text)
|
||||
.join('\n');
|
||||
}
|
||||
rowToString(row, lines) {
|
||||
this.rasterize(row).forEach((rrow, r) => {
|
||||
let str = '';
|
||||
rrow.forEach((col, c) => {
|
||||
const { width } = row[c]; // the width with padding.
|
||||
const wrapWidth = this.negatePadding(row[c]); // the width without padding.
|
||||
let ts = col; // temporary string used during alignment/padding.
|
||||
if (wrapWidth > mixin.stringWidth(col)) {
|
||||
ts += ' '.repeat(wrapWidth - mixin.stringWidth(col));
|
||||
}
|
||||
// align the string within its column.
|
||||
if (row[c].align && row[c].align !== 'left' && this.wrap) {
|
||||
const fn = align[row[c].align];
|
||||
ts = fn(ts, wrapWidth);
|
||||
if (mixin.stringWidth(ts) < wrapWidth) {
|
||||
/* c8 ignore start */
|
||||
const w = width || 0;
|
||||
/* c8 ignore stop */
|
||||
ts += ' '.repeat(w - mixin.stringWidth(ts) - 1);
|
||||
}
|
||||
}
|
||||
// apply border and padding to string.
|
||||
const padding = row[c].padding || [0, 0, 0, 0];
|
||||
if (padding[left]) {
|
||||
str += ' '.repeat(padding[left]);
|
||||
}
|
||||
str += addBorder(row[c], ts, '| ');
|
||||
str += ts;
|
||||
str += addBorder(row[c], ts, ' |');
|
||||
if (padding[right]) {
|
||||
str += ' '.repeat(padding[right]);
|
||||
}
|
||||
// if prior row is span, try to render the
|
||||
// current row on the prior line.
|
||||
if (r === 0 && lines.length > 0) {
|
||||
str = this.renderInline(str, lines[lines.length - 1]);
|
||||
}
|
||||
});
|
||||
// remove trailing whitespace.
|
||||
lines.push({
|
||||
text: str.replace(/ +$/, ''),
|
||||
span: row.span
|
||||
});
|
||||
});
|
||||
return lines;
|
||||
}
|
||||
// if the full 'source' can render in
|
||||
// the target line, do so.
|
||||
renderInline(source, previousLine) {
|
||||
const match = source.match(/^ */);
|
||||
/* c8 ignore start */
|
||||
const leadingWhitespace = match ? match[0].length : 0;
|
||||
/* c8 ignore stop */
|
||||
const target = previousLine.text;
|
||||
const targetTextWidth = mixin.stringWidth(target.trimEnd());
|
||||
if (!previousLine.span) {
|
||||
return source;
|
||||
}
|
||||
// if we're not applying wrapping logic,
|
||||
// just always append to the span.
|
||||
if (!this.wrap) {
|
||||
previousLine.hidden = true;
|
||||
return target + source;
|
||||
}
|
||||
if (leadingWhitespace < targetTextWidth) {
|
||||
return source;
|
||||
}
|
||||
previousLine.hidden = true;
|
||||
return target.trimEnd() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimStart();
|
||||
}
|
||||
rasterize(row) {
|
||||
const rrows = [];
|
||||
const widths = this.columnWidths(row);
|
||||
let wrapped;
|
||||
// word wrap all columns, and create
|
||||
// a data-structure that is easy to rasterize.
|
||||
row.forEach((col, c) => {
|
||||
// leave room for left and right padding.
|
||||
col.width = widths[c];
|
||||
if (this.wrap) {
|
||||
wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n');
|
||||
}
|
||||
else {
|
||||
wrapped = col.text.split('\n');
|
||||
}
|
||||
if (col.border) {
|
||||
wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.');
|
||||
wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'");
|
||||
}
|
||||
// add top and bottom padding.
|
||||
if (col.padding) {
|
||||
wrapped.unshift(...new Array(col.padding[top] || 0).fill(''));
|
||||
wrapped.push(...new Array(col.padding[bottom] || 0).fill(''));
|
||||
}
|
||||
wrapped.forEach((str, r) => {
|
||||
if (!rrows[r]) {
|
||||
rrows.push([]);
|
||||
}
|
||||
const rrow = rrows[r];
|
||||
for (let i = 0; i < c; i++) {
|
||||
if (rrow[i] === undefined) {
|
||||
rrow.push('');
|
||||
}
|
||||
}
|
||||
rrow.push(str);
|
||||
});
|
||||
});
|
||||
return rrows;
|
||||
}
|
||||
negatePadding(col) {
|
||||
/* c8 ignore start */
|
||||
let wrapWidth = col.width || 0;
|
||||
/* c8 ignore stop */
|
||||
if (col.padding) {
|
||||
wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0);
|
||||
}
|
||||
if (col.border) {
|
||||
wrapWidth -= 4;
|
||||
}
|
||||
return wrapWidth;
|
||||
}
|
||||
columnWidths(row) {
|
||||
if (!this.wrap) {
|
||||
return row.map(col => {
|
||||
return col.width || mixin.stringWidth(col.text);
|
||||
});
|
||||
}
|
||||
let unset = row.length;
|
||||
let remainingWidth = this.width;
|
||||
// column widths can be set in config.
|
||||
const widths = row.map(col => {
|
||||
if (col.width) {
|
||||
unset--;
|
||||
remainingWidth -= col.width;
|
||||
return col.width;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
// any unset widths should be calculated.
|
||||
/* c8 ignore start */
|
||||
const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0;
|
||||
/* c8 ignore stop */
|
||||
return widths.map((w, i) => {
|
||||
if (w === undefined) {
|
||||
return Math.max(unsetWidth, _minWidth(row[i]));
|
||||
}
|
||||
return w;
|
||||
});
|
||||
}
|
||||
}
|
||||
function addBorder(col, ts, style) {
|
||||
if (col.border) {
|
||||
if (/[.']-+[.']/.test(ts)) {
|
||||
return '';
|
||||
}
|
||||
if (ts.trim().length !== 0) {
|
||||
return style;
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// calculates the minimum width of
|
||||
// a column, based on padding preferences.
|
||||
function _minWidth(col) {
|
||||
const padding = col.padding || [];
|
||||
const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0);
|
||||
if (col.border) {
|
||||
return minWidth + 4;
|
||||
}
|
||||
return minWidth;
|
||||
}
|
||||
function getWindowWidth() {
|
||||
/* c8 ignore start */
|
||||
if (typeof process === 'object' && process.stdout && process.stdout.columns) {
|
||||
return process.stdout.columns;
|
||||
}
|
||||
return 80;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
function alignRight(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
if (strWidth < width) {
|
||||
return ' '.repeat(width - strWidth) + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function alignCenter(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
/* c8 ignore start */
|
||||
if (strWidth >= width) {
|
||||
return str;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return ' '.repeat((width - strWidth) >> 1) + str;
|
||||
}
|
||||
let mixin;
|
||||
function cliui(opts, _mixin) {
|
||||
mixin = _mixin;
|
||||
return new UI({
|
||||
/* c8 ignore start */
|
||||
width: (opts === null || opts === void 0 ? void 0 : opts.width) || getWindowWidth(),
|
||||
wrap: opts === null || opts === void 0 ? void 0 : opts.wrap
|
||||
/* c8 ignore stop */
|
||||
});
|
||||
}
|
||||
|
||||
// Bootstrap cliui with CommonJS dependencies:
|
||||
const stringWidth = require('string-width-cjs');
|
||||
const stripAnsi = require('strip-ansi-cjs');
|
||||
const wrap = require('wrap-ansi-cjs');
|
||||
function ui(opts) {
|
||||
return cliui(opts, {
|
||||
stringWidth,
|
||||
stripAnsi,
|
||||
wrap
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = ui;
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
interface UIOptions {
|
||||
width: number;
|
||||
wrap?: boolean;
|
||||
rows?: string[];
|
||||
}
|
||||
interface Column {
|
||||
text: string;
|
||||
width?: number;
|
||||
align?: "right" | "left" | "center";
|
||||
padding: number[];
|
||||
border?: boolean;
|
||||
}
|
||||
interface ColumnArray extends Array<Column> {
|
||||
span: boolean;
|
||||
}
|
||||
interface Line {
|
||||
hidden?: boolean;
|
||||
text: string;
|
||||
span?: boolean;
|
||||
}
|
||||
declare class UI {
|
||||
width: number;
|
||||
wrap: boolean;
|
||||
rows: ColumnArray[];
|
||||
constructor(opts: UIOptions);
|
||||
span(...args: ColumnArray): void;
|
||||
resetOutput(): void;
|
||||
div(...args: (Column | string)[]): ColumnArray;
|
||||
private shouldApplyLayoutDSL;
|
||||
private applyLayoutDSL;
|
||||
private colFromString;
|
||||
private measurePadding;
|
||||
toString(): string;
|
||||
rowToString(row: ColumnArray, lines: Line[]): Line[];
|
||||
// if the full 'source' can render in
|
||||
// the target line, do so.
|
||||
private renderInline;
|
||||
private rasterize;
|
||||
private negatePadding;
|
||||
private columnWidths;
|
||||
}
|
||||
declare function ui(opts: UIOptions): UI;
|
||||
export { ui as default };
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
'use strict';
|
||||
const align = {
|
||||
right: alignRight,
|
||||
center: alignCenter
|
||||
};
|
||||
const top = 0;
|
||||
const right = 1;
|
||||
const bottom = 2;
|
||||
const left = 3;
|
||||
export class UI {
|
||||
constructor(opts) {
|
||||
var _a;
|
||||
this.width = opts.width;
|
||||
/* c8 ignore start */
|
||||
this.wrap = (_a = opts.wrap) !== null && _a !== void 0 ? _a : true;
|
||||
/* c8 ignore stop */
|
||||
this.rows = [];
|
||||
}
|
||||
span(...args) {
|
||||
const cols = this.div(...args);
|
||||
cols.span = true;
|
||||
}
|
||||
resetOutput() {
|
||||
this.rows = [];
|
||||
}
|
||||
div(...args) {
|
||||
if (args.length === 0) {
|
||||
this.div('');
|
||||
}
|
||||
if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') {
|
||||
return this.applyLayoutDSL(args[0]);
|
||||
}
|
||||
const cols = args.map(arg => {
|
||||
if (typeof arg === 'string') {
|
||||
return this.colFromString(arg);
|
||||
}
|
||||
return arg;
|
||||
});
|
||||
this.rows.push(cols);
|
||||
return cols;
|
||||
}
|
||||
shouldApplyLayoutDSL(...args) {
|
||||
return args.length === 1 && typeof args[0] === 'string' &&
|
||||
/[\t\n]/.test(args[0]);
|
||||
}
|
||||
applyLayoutDSL(str) {
|
||||
const rows = str.split('\n').map(row => row.split('\t'));
|
||||
let leftColumnWidth = 0;
|
||||
// simple heuristic for layout, make sure the
|
||||
// second column lines up along the left-hand.
|
||||
// don't allow the first column to take up more
|
||||
// than 50% of the screen.
|
||||
rows.forEach(columns => {
|
||||
if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) {
|
||||
leftColumnWidth = Math.min(Math.floor(this.width * 0.5), mixin.stringWidth(columns[0]));
|
||||
}
|
||||
});
|
||||
// generate a table:
|
||||
// replacing ' ' with padding calculations.
|
||||
// using the algorithmically generated width.
|
||||
rows.forEach(columns => {
|
||||
this.div(...columns.map((r, i) => {
|
||||
return {
|
||||
text: r.trim(),
|
||||
padding: this.measurePadding(r),
|
||||
width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
|
||||
};
|
||||
}));
|
||||
});
|
||||
return this.rows[this.rows.length - 1];
|
||||
}
|
||||
colFromString(text) {
|
||||
return {
|
||||
text,
|
||||
padding: this.measurePadding(text)
|
||||
};
|
||||
}
|
||||
measurePadding(str) {
|
||||
// measure padding without ansi escape codes
|
||||
const noAnsi = mixin.stripAnsi(str);
|
||||
return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length];
|
||||
}
|
||||
toString() {
|
||||
const lines = [];
|
||||
this.rows.forEach(row => {
|
||||
this.rowToString(row, lines);
|
||||
});
|
||||
// don't display any lines with the
|
||||
// hidden flag set.
|
||||
return lines
|
||||
.filter(line => !line.hidden)
|
||||
.map(line => line.text)
|
||||
.join('\n');
|
||||
}
|
||||
rowToString(row, lines) {
|
||||
this.rasterize(row).forEach((rrow, r) => {
|
||||
let str = '';
|
||||
rrow.forEach((col, c) => {
|
||||
const { width } = row[c]; // the width with padding.
|
||||
const wrapWidth = this.negatePadding(row[c]); // the width without padding.
|
||||
let ts = col; // temporary string used during alignment/padding.
|
||||
if (wrapWidth > mixin.stringWidth(col)) {
|
||||
ts += ' '.repeat(wrapWidth - mixin.stringWidth(col));
|
||||
}
|
||||
// align the string within its column.
|
||||
if (row[c].align && row[c].align !== 'left' && this.wrap) {
|
||||
const fn = align[row[c].align];
|
||||
ts = fn(ts, wrapWidth);
|
||||
if (mixin.stringWidth(ts) < wrapWidth) {
|
||||
/* c8 ignore start */
|
||||
const w = width || 0;
|
||||
/* c8 ignore stop */
|
||||
ts += ' '.repeat(w - mixin.stringWidth(ts) - 1);
|
||||
}
|
||||
}
|
||||
// apply border and padding to string.
|
||||
const padding = row[c].padding || [0, 0, 0, 0];
|
||||
if (padding[left]) {
|
||||
str += ' '.repeat(padding[left]);
|
||||
}
|
||||
str += addBorder(row[c], ts, '| ');
|
||||
str += ts;
|
||||
str += addBorder(row[c], ts, ' |');
|
||||
if (padding[right]) {
|
||||
str += ' '.repeat(padding[right]);
|
||||
}
|
||||
// if prior row is span, try to render the
|
||||
// current row on the prior line.
|
||||
if (r === 0 && lines.length > 0) {
|
||||
str = this.renderInline(str, lines[lines.length - 1]);
|
||||
}
|
||||
});
|
||||
// remove trailing whitespace.
|
||||
lines.push({
|
||||
text: str.replace(/ +$/, ''),
|
||||
span: row.span
|
||||
});
|
||||
});
|
||||
return lines;
|
||||
}
|
||||
// if the full 'source' can render in
|
||||
// the target line, do so.
|
||||
renderInline(source, previousLine) {
|
||||
const match = source.match(/^ */);
|
||||
/* c8 ignore start */
|
||||
const leadingWhitespace = match ? match[0].length : 0;
|
||||
/* c8 ignore stop */
|
||||
const target = previousLine.text;
|
||||
const targetTextWidth = mixin.stringWidth(target.trimEnd());
|
||||
if (!previousLine.span) {
|
||||
return source;
|
||||
}
|
||||
// if we're not applying wrapping logic,
|
||||
// just always append to the span.
|
||||
if (!this.wrap) {
|
||||
previousLine.hidden = true;
|
||||
return target + source;
|
||||
}
|
||||
if (leadingWhitespace < targetTextWidth) {
|
||||
return source;
|
||||
}
|
||||
previousLine.hidden = true;
|
||||
return target.trimEnd() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimStart();
|
||||
}
|
||||
rasterize(row) {
|
||||
const rrows = [];
|
||||
const widths = this.columnWidths(row);
|
||||
let wrapped;
|
||||
// word wrap all columns, and create
|
||||
// a data-structure that is easy to rasterize.
|
||||
row.forEach((col, c) => {
|
||||
// leave room for left and right padding.
|
||||
col.width = widths[c];
|
||||
if (this.wrap) {
|
||||
wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n');
|
||||
}
|
||||
else {
|
||||
wrapped = col.text.split('\n');
|
||||
}
|
||||
if (col.border) {
|
||||
wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.');
|
||||
wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'");
|
||||
}
|
||||
// add top and bottom padding.
|
||||
if (col.padding) {
|
||||
wrapped.unshift(...new Array(col.padding[top] || 0).fill(''));
|
||||
wrapped.push(...new Array(col.padding[bottom] || 0).fill(''));
|
||||
}
|
||||
wrapped.forEach((str, r) => {
|
||||
if (!rrows[r]) {
|
||||
rrows.push([]);
|
||||
}
|
||||
const rrow = rrows[r];
|
||||
for (let i = 0; i < c; i++) {
|
||||
if (rrow[i] === undefined) {
|
||||
rrow.push('');
|
||||
}
|
||||
}
|
||||
rrow.push(str);
|
||||
});
|
||||
});
|
||||
return rrows;
|
||||
}
|
||||
negatePadding(col) {
|
||||
/* c8 ignore start */
|
||||
let wrapWidth = col.width || 0;
|
||||
/* c8 ignore stop */
|
||||
if (col.padding) {
|
||||
wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0);
|
||||
}
|
||||
if (col.border) {
|
||||
wrapWidth -= 4;
|
||||
}
|
||||
return wrapWidth;
|
||||
}
|
||||
columnWidths(row) {
|
||||
if (!this.wrap) {
|
||||
return row.map(col => {
|
||||
return col.width || mixin.stringWidth(col.text);
|
||||
});
|
||||
}
|
||||
let unset = row.length;
|
||||
let remainingWidth = this.width;
|
||||
// column widths can be set in config.
|
||||
const widths = row.map(col => {
|
||||
if (col.width) {
|
||||
unset--;
|
||||
remainingWidth -= col.width;
|
||||
return col.width;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
// any unset widths should be calculated.
|
||||
/* c8 ignore start */
|
||||
const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0;
|
||||
/* c8 ignore stop */
|
||||
return widths.map((w, i) => {
|
||||
if (w === undefined) {
|
||||
return Math.max(unsetWidth, _minWidth(row[i]));
|
||||
}
|
||||
return w;
|
||||
});
|
||||
}
|
||||
}
|
||||
function addBorder(col, ts, style) {
|
||||
if (col.border) {
|
||||
if (/[.']-+[.']/.test(ts)) {
|
||||
return '';
|
||||
}
|
||||
if (ts.trim().length !== 0) {
|
||||
return style;
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// calculates the minimum width of
|
||||
// a column, based on padding preferences.
|
||||
function _minWidth(col) {
|
||||
const padding = col.padding || [];
|
||||
const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0);
|
||||
if (col.border) {
|
||||
return minWidth + 4;
|
||||
}
|
||||
return minWidth;
|
||||
}
|
||||
function getWindowWidth() {
|
||||
/* c8 ignore start */
|
||||
if (typeof process === 'object' && process.stdout && process.stdout.columns) {
|
||||
return process.stdout.columns;
|
||||
}
|
||||
return 80;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
function alignRight(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
if (strWidth < width) {
|
||||
return ' '.repeat(width - strWidth) + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function alignCenter(str, width) {
|
||||
str = str.trim();
|
||||
const strWidth = mixin.stringWidth(str);
|
||||
/* c8 ignore start */
|
||||
if (strWidth >= width) {
|
||||
return str;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return ' '.repeat((width - strWidth) >> 1) + str;
|
||||
}
|
||||
let mixin;
|
||||
export function cliui(opts, _mixin) {
|
||||
mixin = _mixin;
|
||||
return new UI({
|
||||
/* c8 ignore start */
|
||||
width: (opts === null || opts === void 0 ? void 0 : opts.width) || getWindowWidth(),
|
||||
wrap: opts === null || opts === void 0 ? void 0 : opts.wrap
|
||||
/* c8 ignore stop */
|
||||
});
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// Bootstrap cliui with ESM dependencies:
|
||||
import { cliui } from './build/lib/index.js'
|
||||
|
||||
import stringWidth from 'string-width'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import wrap from 'wrap-ansi'
|
||||
|
||||
export default function ui (opts) {
|
||||
return cliui(opts, {
|
||||
stringWidth,
|
||||
stripAnsi,
|
||||
wrap
|
||||
})
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"name": "@isaacs/cliui",
|
||||
"version": "8.0.2",
|
||||
"description": "easily create complex multi-column command-line-interfaces",
|
||||
"main": "build/index.cjs",
|
||||
"exports": {
|
||||
".": [
|
||||
{
|
||||
"import": "./index.mjs",
|
||||
"require": "./build/index.cjs"
|
||||
},
|
||||
"./build/index.cjs"
|
||||
]
|
||||
},
|
||||
"type": "module",
|
||||
"module": "./index.mjs",
|
||||
"scripts": {
|
||||
"check": "standardx '**/*.ts' && standardx '**/*.js' && standardx '**/*.cjs'",
|
||||
"fix": "standardx --fix '**/*.ts' && standardx --fix '**/*.js' && standardx --fix '**/*.cjs'",
|
||||
"pretest": "rimraf build && tsc -p tsconfig.test.json && cross-env NODE_ENV=test npm run build:cjs",
|
||||
"test": "c8 mocha ./test/*.cjs",
|
||||
"test:esm": "c8 mocha ./test/**/*.mjs",
|
||||
"postest": "check",
|
||||
"coverage": "c8 report --check-coverage",
|
||||
"precompile": "rimraf build",
|
||||
"compile": "tsc",
|
||||
"postcompile": "npm run build:cjs",
|
||||
"build:cjs": "rollup -c",
|
||||
"prepare": "npm run compile"
|
||||
},
|
||||
"repository": "yargs/cliui",
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"**/example/**"
|
||||
],
|
||||
"globals": [
|
||||
"it"
|
||||
]
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
"command-line",
|
||||
"layout",
|
||||
"design",
|
||||
"console",
|
||||
"wrap",
|
||||
"table"
|
||||
],
|
||||
"author": "Ben Coe <ben@npmjs.com>",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^5.1.2",
|
||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
||||
"strip-ansi": "^7.0.1",
|
||||
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
|
||||
"wrap-ansi": "^8.1.0",
|
||||
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.27",
|
||||
"@typescript-eslint/eslint-plugin": "^4.0.0",
|
||||
"@typescript-eslint/parser": "^4.0.0",
|
||||
"c8": "^7.3.0",
|
||||
"chai": "^4.2.0",
|
||||
"chalk": "^4.1.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^7.6.0",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"gts": "^3.0.0",
|
||||
"mocha": "^10.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.23.1",
|
||||
"rollup-plugin-ts": "^3.0.2",
|
||||
"standardx": "^7.0.0",
|
||||
"typescript": "^4.0.0"
|
||||
},
|
||||
"files": [
|
||||
"build",
|
||||
"index.mjs",
|
||||
"!*.d.ts"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Copied from Node.js to ease compatibility in PR.
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
quote_type = single
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
# Changelog
|
||||
|
||||
## [0.11.0](https://github.com/pkgjs/parseargs/compare/v0.10.0...v0.11.0) (2022-10-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add `default` option parameter ([#142](https://github.com/pkgjs/parseargs/issues/142)) ([cd20847](https://github.com/pkgjs/parseargs/commit/cd20847a00b2f556aa9c085ac83b942c60868ec1))
|
||||
|
||||
## [0.10.0](https://github.com/pkgjs/parseargs/compare/v0.9.1...v0.10.0) (2022-07-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add parsed meta-data to returned properties ([#129](https://github.com/pkgjs/parseargs/issues/129)) ([91bfb4d](https://github.com/pkgjs/parseargs/commit/91bfb4d3f7b6937efab1b27c91c45d1205f1497e))
|
||||
|
||||
## [0.9.1](https://github.com/pkgjs/parseargs/compare/v0.9.0...v0.9.1) (2022-06-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **runtime:** support node 14+ ([#135](https://github.com/pkgjs/parseargs/issues/135)) ([6a1c5a6](https://github.com/pkgjs/parseargs/commit/6a1c5a6f7cadf2f035e004027e2742e3c4ce554b))
|
||||
|
||||
## [0.9.0](https://github.com/pkgjs/parseargs/compare/v0.8.0...v0.9.0) (2022-05-23)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* drop handling of electron arguments (#121)
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* drop handling of electron arguments ([#121](https://github.com/pkgjs/parseargs/issues/121)) ([a2ffd53](https://github.com/pkgjs/parseargs/commit/a2ffd537c244a062371522b955acb45a404fc9f2))
|
||||
|
||||
## [0.8.0](https://github.com/pkgjs/parseargs/compare/v0.7.1...v0.8.0) (2022-05-16)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* switch type:string option arguments to greedy, but with error for suspect cases in strict mode (#88)
|
||||
* positionals now opt-in when strict:true (#116)
|
||||
* create result.values with null prototype (#111)
|
||||
|
||||
### Features
|
||||
|
||||
* create result.values with null prototype ([#111](https://github.com/pkgjs/parseargs/issues/111)) ([9d539c3](https://github.com/pkgjs/parseargs/commit/9d539c3d57f269c160e74e0656ad4fa84ff92ec2))
|
||||
* positionals now opt-in when strict:true ([#116](https://github.com/pkgjs/parseargs/issues/116)) ([3643338](https://github.com/pkgjs/parseargs/commit/364333826b746e8a7dc5505b4b22fd19ac51df3b))
|
||||
* switch type:string option arguments to greedy, but with error for suspect cases in strict mode ([#88](https://github.com/pkgjs/parseargs/issues/88)) ([c2b5e72](https://github.com/pkgjs/parseargs/commit/c2b5e72161991dfdc535909f1327cc9b970fe7e8))
|
||||
|
||||
### [0.7.1](https://github.com/pkgjs/parseargs/compare/v0.7.0...v0.7.1) (2022-04-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* resist pollution ([#106](https://github.com/pkgjs/parseargs/issues/106)) ([ecf2dec](https://github.com/pkgjs/parseargs/commit/ecf2dece0a9f2a76d789384d5d71c68ffe64022a))
|
||||
|
||||
## [0.7.0](https://github.com/pkgjs/parseargs/compare/v0.6.0...v0.7.0) (2022-04-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add strict mode to parser ([#74](https://github.com/pkgjs/parseargs/issues/74)) ([8267d02](https://github.com/pkgjs/parseargs/commit/8267d02083a87b8b8a71fcce08348d1e031ea91c))
|
||||
|
||||
## [0.6.0](https://github.com/pkgjs/parseargs/compare/v0.5.0...v0.6.0) (2022-04-11)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* rework results to remove redundant `flags` property and store value true for boolean options (#83)
|
||||
* switch to existing ERR_INVALID_ARG_VALUE (#97)
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* rework results to remove redundant `flags` property and store value true for boolean options ([#83](https://github.com/pkgjs/parseargs/issues/83)) ([be153db](https://github.com/pkgjs/parseargs/commit/be153dbed1d488cb7b6e27df92f601ba7337713d))
|
||||
* switch to existing ERR_INVALID_ARG_VALUE ([#97](https://github.com/pkgjs/parseargs/issues/97)) ([084a23f](https://github.com/pkgjs/parseargs/commit/084a23f9fde2da030b159edb1c2385f24579ce40))
|
||||
|
||||
## [0.5.0](https://github.com/pkgjs/parseargs/compare/v0.4.0...v0.5.0) (2022-04-10)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* Require type to be specified for each supplied option (#95)
|
||||
|
||||
### Features
|
||||
|
||||
* Require type to be specified for each supplied option ([#95](https://github.com/pkgjs/parseargs/issues/95)) ([02cd018](https://github.com/pkgjs/parseargs/commit/02cd01885b8aaa59f2db8308f2d4479e64340068))
|
||||
|
||||
## [0.4.0](https://github.com/pkgjs/parseargs/compare/v0.3.0...v0.4.0) (2022-03-12)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* parsing, revisit short option groups, add support for combined short and value (#75)
|
||||
* restructure configuration to take options bag (#63)
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* parsing, revisit short option groups, add support for combined short and value ([#75](https://github.com/pkgjs/parseargs/issues/75)) ([a92600f](https://github.com/pkgjs/parseargs/commit/a92600fa6c214508ab1e016fa55879a314f541af))
|
||||
* restructure configuration to take options bag ([#63](https://github.com/pkgjs/parseargs/issues/63)) ([b412095](https://github.com/pkgjs/parseargs/commit/b4120957d90e809ee8b607b06e747d3e6a6b213e))
|
||||
|
||||
## [0.3.0](https://github.com/pkgjs/parseargs/compare/v0.2.0...v0.3.0) (2022-02-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **parser:** support short-option groups ([#59](https://github.com/pkgjs/parseargs/issues/59)) ([882067b](https://github.com/pkgjs/parseargs/commit/882067bc2d7cbc6b796f8e5a079a99bc99d4e6ba))
|
||||
|
||||
## [0.2.0](https://github.com/pkgjs/parseargs/compare/v0.1.1...v0.2.0) (2022-02-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* basic support for shorts ([#50](https://github.com/pkgjs/parseargs/issues/50)) ([a2f36d7](https://github.com/pkgjs/parseargs/commit/a2f36d7da4145af1c92f76806b7fe2baf6beeceb))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* always store value for a=b ([#43](https://github.com/pkgjs/parseargs/issues/43)) ([a85e8dc](https://github.com/pkgjs/parseargs/commit/a85e8dc06379fd2696ee195cc625de8fac6aee42))
|
||||
* support single dash as positional ([#49](https://github.com/pkgjs/parseargs/issues/49)) ([d795bf8](https://github.com/pkgjs/parseargs/commit/d795bf877d068fd67aec381f30b30b63f97109ad))
|
||||
|
||||
### [0.1.1](https://github.com/pkgjs/parseargs/compare/v0.1.0...v0.1.1) (2022-01-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* only use arrays in results for multiples ([#42](https://github.com/pkgjs/parseargs/issues/42)) ([c357584](https://github.com/pkgjs/parseargs/commit/c357584847912506319ed34a0840080116f4fd65))
|
||||
|
||||
## 0.1.0 (2022-01-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* expand scenarios covered by default arguments for environments ([#20](https://github.com/pkgjs/parseargs/issues/20)) ([582ada7](https://github.com/pkgjs/parseargs/commit/582ada7be0eca3a73d6e0bd016e7ace43449fa4c))
|
||||
* update readme and include contributing guidelines ([8edd6fc](https://github.com/pkgjs/parseargs/commit/8edd6fc863cd705f6fac732724159ebe8065a2b0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not strip excess leading dashes on long option names ([#21](https://github.com/pkgjs/parseargs/issues/21)) ([f848590](https://github.com/pkgjs/parseargs/commit/f848590ebf3249ed5979ff47e003fa6e1a8ec5c0))
|
||||
* name & readme ([3f057c1](https://github.com/pkgjs/parseargs/commit/3f057c1b158a1bdbe878c64b57460c58e56e465f))
|
||||
* package.json values ([9bac300](https://github.com/pkgjs/parseargs/commit/9bac300e00cd76c77076bf9e75e44f8929512da9))
|
||||
* update readme name ([957d8d9](https://github.com/pkgjs/parseargs/commit/957d8d96e1dcb48297c0a14345d44c0123b2883e))
|
||||
|
||||
|
||||
### Build System
|
||||
|
||||
* first release as minor ([421c6e2](https://github.com/pkgjs/parseargs/commit/421c6e2569a8668ad14fac5a5af5be60479a7571))
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+413
@@ -0,0 +1,413 @@
|
||||
<!-- omit in toc -->
|
||||
# parseArgs
|
||||
|
||||
[![Coverage][coverage-image]][coverage-url]
|
||||
|
||||
Polyfill of `util.parseArgs()`
|
||||
|
||||
## `util.parseArgs([config])`
|
||||
|
||||
<!-- YAML
|
||||
added: v18.3.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/43459
|
||||
description: add support for returning detailed parse information
|
||||
using `tokens` in input `config` and returned properties.
|
||||
-->
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
* `config` {Object} Used to provide arguments for parsing and to configure
|
||||
the parser. `config` supports the following properties:
|
||||
* `args` {string\[]} array of argument strings. **Default:** `process.argv`
|
||||
with `execPath` and `filename` removed.
|
||||
* `options` {Object} Used to describe arguments known to the parser.
|
||||
Keys of `options` are the long names of options and values are an
|
||||
{Object} accepting the following properties:
|
||||
* `type` {string} Type of argument, which must be either `boolean` or `string`.
|
||||
* `multiple` {boolean} Whether this option can be provided multiple
|
||||
times. If `true`, all values will be collected in an array. If
|
||||
`false`, values for the option are last-wins. **Default:** `false`.
|
||||
* `short` {string} A single character alias for the option.
|
||||
* `default` {string | boolean | string\[] | boolean\[]} The default option
|
||||
value when it is not set by args. It must be of the same type as the
|
||||
the `type` property. When `multiple` is `true`, it must be an array.
|
||||
* `strict` {boolean} Should an error be thrown when unknown arguments
|
||||
are encountered, or when arguments are passed that do not match the
|
||||
`type` configured in `options`.
|
||||
**Default:** `true`.
|
||||
* `allowPositionals` {boolean} Whether this command accepts positional
|
||||
arguments.
|
||||
**Default:** `false` if `strict` is `true`, otherwise `true`.
|
||||
* `tokens` {boolean} Return the parsed tokens. This is useful for extending
|
||||
the built-in behavior, from adding additional checks through to reprocessing
|
||||
the tokens in different ways.
|
||||
**Default:** `false`.
|
||||
|
||||
* Returns: {Object} The parsed command line arguments:
|
||||
* `values` {Object} A mapping of parsed option names with their {string}
|
||||
or {boolean} values.
|
||||
* `positionals` {string\[]} Positional arguments.
|
||||
* `tokens` {Object\[] | undefined} See [parseArgs tokens](#parseargs-tokens)
|
||||
section. Only returned if `config` includes `tokens: true`.
|
||||
|
||||
Provides a higher level API for command-line argument parsing than interacting
|
||||
with `process.argv` directly. Takes a specification for the expected arguments
|
||||
and returns a structured object with the parsed options and positionals.
|
||||
|
||||
```mjs
|
||||
import { parseArgs } from 'node:util';
|
||||
const args = ['-f', '--bar', 'b'];
|
||||
const options = {
|
||||
foo: {
|
||||
type: 'boolean',
|
||||
short: 'f'
|
||||
},
|
||||
bar: {
|
||||
type: 'string'
|
||||
}
|
||||
};
|
||||
const {
|
||||
values,
|
||||
positionals
|
||||
} = parseArgs({ args, options });
|
||||
console.log(values, positionals);
|
||||
// Prints: [Object: null prototype] { foo: true, bar: 'b' } []
|
||||
```
|
||||
|
||||
```cjs
|
||||
const { parseArgs } = require('node:util');
|
||||
const args = ['-f', '--bar', 'b'];
|
||||
const options = {
|
||||
foo: {
|
||||
type: 'boolean',
|
||||
short: 'f'
|
||||
},
|
||||
bar: {
|
||||
type: 'string'
|
||||
}
|
||||
};
|
||||
const {
|
||||
values,
|
||||
positionals
|
||||
} = parseArgs({ args, options });
|
||||
console.log(values, positionals);
|
||||
// Prints: [Object: null prototype] { foo: true, bar: 'b' } []
|
||||
```
|
||||
|
||||
`util.parseArgs` is experimental and behavior may change. Join the
|
||||
conversation in [pkgjs/parseargs][] to contribute to the design.
|
||||
|
||||
### `parseArgs` `tokens`
|
||||
|
||||
Detailed parse information is available for adding custom behaviours by
|
||||
specifying `tokens: true` in the configuration.
|
||||
The returned tokens have properties describing:
|
||||
|
||||
* all tokens
|
||||
* `kind` {string} One of 'option', 'positional', or 'option-terminator'.
|
||||
* `index` {number} Index of element in `args` containing token. So the
|
||||
source argument for a token is `args[token.index]`.
|
||||
* option tokens
|
||||
* `name` {string} Long name of option.
|
||||
* `rawName` {string} How option used in args, like `-f` of `--foo`.
|
||||
* `value` {string | undefined} Option value specified in args.
|
||||
Undefined for boolean options.
|
||||
* `inlineValue` {boolean | undefined} Whether option value specified inline,
|
||||
like `--foo=bar`.
|
||||
* positional tokens
|
||||
* `value` {string} The value of the positional argument in args (i.e. `args[index]`).
|
||||
* option-terminator token
|
||||
|
||||
The returned tokens are in the order encountered in the input args. Options
|
||||
that appear more than once in args produce a token for each use. Short option
|
||||
groups like `-xy` expand to a token for each option. So `-xxx` produces
|
||||
three tokens.
|
||||
|
||||
For example to use the returned tokens to add support for a negated option
|
||||
like `--no-color`, the tokens can be reprocessed to change the value stored
|
||||
for the negated option.
|
||||
|
||||
```mjs
|
||||
import { parseArgs } from 'node:util';
|
||||
|
||||
const options = {
|
||||
'color': { type: 'boolean' },
|
||||
'no-color': { type: 'boolean' },
|
||||
'logfile': { type: 'string' },
|
||||
'no-logfile': { type: 'boolean' },
|
||||
};
|
||||
const { values, tokens } = parseArgs({ options, tokens: true });
|
||||
|
||||
// Reprocess the option tokens and overwrite the returned values.
|
||||
tokens
|
||||
.filter((token) => token.kind === 'option')
|
||||
.forEach((token) => {
|
||||
if (token.name.startsWith('no-')) {
|
||||
// Store foo:false for --no-foo
|
||||
const positiveName = token.name.slice(3);
|
||||
values[positiveName] = false;
|
||||
delete values[token.name];
|
||||
} else {
|
||||
// Resave value so last one wins if both --foo and --no-foo.
|
||||
values[token.name] = token.value ?? true;
|
||||
}
|
||||
});
|
||||
|
||||
const color = values.color;
|
||||
const logfile = values.logfile ?? 'default.log';
|
||||
|
||||
console.log({ logfile, color });
|
||||
```
|
||||
|
||||
```cjs
|
||||
const { parseArgs } = require('node:util');
|
||||
|
||||
const options = {
|
||||
'color': { type: 'boolean' },
|
||||
'no-color': { type: 'boolean' },
|
||||
'logfile': { type: 'string' },
|
||||
'no-logfile': { type: 'boolean' },
|
||||
};
|
||||
const { values, tokens } = parseArgs({ options, tokens: true });
|
||||
|
||||
// Reprocess the option tokens and overwrite the returned values.
|
||||
tokens
|
||||
.filter((token) => token.kind === 'option')
|
||||
.forEach((token) => {
|
||||
if (token.name.startsWith('no-')) {
|
||||
// Store foo:false for --no-foo
|
||||
const positiveName = token.name.slice(3);
|
||||
values[positiveName] = false;
|
||||
delete values[token.name];
|
||||
} else {
|
||||
// Resave value so last one wins if both --foo and --no-foo.
|
||||
values[token.name] = token.value ?? true;
|
||||
}
|
||||
});
|
||||
|
||||
const color = values.color;
|
||||
const logfile = values.logfile ?? 'default.log';
|
||||
|
||||
console.log({ logfile, color });
|
||||
```
|
||||
|
||||
Example usage showing negated options, and when an option is used
|
||||
multiple ways then last one wins.
|
||||
|
||||
```console
|
||||
$ node negate.js
|
||||
{ logfile: 'default.log', color: undefined }
|
||||
$ node negate.js --no-logfile --no-color
|
||||
{ logfile: false, color: false }
|
||||
$ node negate.js --logfile=test.log --color
|
||||
{ logfile: 'test.log', color: true }
|
||||
$ node negate.js --no-logfile --logfile=test.log --color --no-color
|
||||
{ logfile: 'test.log', color: false }
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
<!-- omit in toc -->
|
||||
## Table of Contents
|
||||
- [`util.parseArgs([config])`](#utilparseargsconfig)
|
||||
- [Scope](#scope)
|
||||
- [Version Matchups](#version-matchups)
|
||||
- [🚀 Getting Started](#-getting-started)
|
||||
- [🙌 Contributing](#-contributing)
|
||||
- [💡 `process.mainArgs` Proposal](#-processmainargs-proposal)
|
||||
- [Implementation:](#implementation)
|
||||
- [📃 Examples](#-examples)
|
||||
- [F.A.Qs](#faqs)
|
||||
- [Links & Resources](#links--resources)
|
||||
|
||||
-----
|
||||
|
||||
## Scope
|
||||
|
||||
It is already possible to build great arg parsing modules on top of what Node.js provides; the prickly API is abstracted away by these modules. Thus, process.parseArgs() is not necessarily intended for library authors; it is intended for developers of simple CLI tools, ad-hoc scripts, deployed Node.js applications, and learning materials.
|
||||
|
||||
It is exceedingly difficult to provide an API which would both be friendly to these Node.js users while being extensible enough for libraries to build upon. We chose to prioritize these use cases because these are currently not well-served by Node.js' API.
|
||||
|
||||
----
|
||||
|
||||
## Version Matchups
|
||||
|
||||
| Node.js | @pkgjs/parseArgs |
|
||||
| -- | -- |
|
||||
| [v18.3.0](https://nodejs.org/docs/latest-v18.x/api/util.html#utilparseargsconfig) | [v0.9.1](https://github.com/pkgjs/parseargs/tree/v0.9.1#utilparseargsconfig) |
|
||||
| [v16.17.0](https://nodejs.org/dist/latest-v16.x/docs/api/util.html#utilparseargsconfig), [v18.7.0](https://nodejs.org/docs/latest-v18.x/api/util.html#utilparseargsconfig) | [0.10.0](https://github.com/pkgjs/parseargs/tree/v0.10.0#utilparseargsconfig) |
|
||||
|
||||
----
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
1. **Install dependencies.**
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. **Open the index.js file and start editing!**
|
||||
|
||||
3. **Test your code by calling parseArgs through our test file**
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
## 🙌 Contributing
|
||||
|
||||
Any person who wants to contribute to the initiative is welcome! Please first read the [Contributing Guide](CONTRIBUTING.md)
|
||||
|
||||
Additionally, reading the [`Examples w/ Output`](#-examples-w-output) section of this document will be the best way to familiarize yourself with the target expected behavior for parseArgs() once it is fully implemented.
|
||||
|
||||
This package was implemented using [tape](https://www.npmjs.com/package/tape) as its test harness.
|
||||
|
||||
----
|
||||
|
||||
## 💡 `process.mainArgs` Proposal
|
||||
|
||||
> Note: This can be moved forward independently of the `util.parseArgs()` proposal/work.
|
||||
|
||||
### Implementation:
|
||||
|
||||
```javascript
|
||||
process.mainArgs = process.argv.slice(process._exec ? 1 : 2)
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
## 📃 Examples
|
||||
|
||||
```js
|
||||
const { parseArgs } = require('@pkgjs/parseargs');
|
||||
```
|
||||
|
||||
```js
|
||||
const { parseArgs } = require('@pkgjs/parseargs');
|
||||
// specify the options that may be used
|
||||
const options = {
|
||||
foo: { type: 'string'},
|
||||
bar: { type: 'boolean' },
|
||||
};
|
||||
const args = ['--foo=a', '--bar'];
|
||||
const { values, positionals } = parseArgs({ args, options });
|
||||
// values = { foo: 'a', bar: true }
|
||||
// positionals = []
|
||||
```
|
||||
|
||||
```js
|
||||
const { parseArgs } = require('@pkgjs/parseargs');
|
||||
// type:string & multiple
|
||||
const options = {
|
||||
foo: {
|
||||
type: 'string',
|
||||
multiple: true,
|
||||
},
|
||||
};
|
||||
const args = ['--foo=a', '--foo', 'b'];
|
||||
const { values, positionals } = parseArgs({ args, options });
|
||||
// values = { foo: [ 'a', 'b' ] }
|
||||
// positionals = []
|
||||
```
|
||||
|
||||
```js
|
||||
const { parseArgs } = require('@pkgjs/parseargs');
|
||||
// shorts
|
||||
const options = {
|
||||
foo: {
|
||||
short: 'f',
|
||||
type: 'boolean'
|
||||
},
|
||||
};
|
||||
const args = ['-f', 'b'];
|
||||
const { values, positionals } = parseArgs({ args, options, allowPositionals: true });
|
||||
// values = { foo: true }
|
||||
// positionals = ['b']
|
||||
```
|
||||
|
||||
```js
|
||||
const { parseArgs } = require('@pkgjs/parseargs');
|
||||
// unconfigured
|
||||
const options = {};
|
||||
const args = ['-f', '--foo=a', '--bar', 'b'];
|
||||
const { values, positionals } = parseArgs({ strict: false, args, options, allowPositionals: true });
|
||||
// values = { f: true, foo: 'a', bar: true }
|
||||
// positionals = ['b']
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
## F.A.Qs
|
||||
|
||||
- Is `cmd --foo=bar baz` the same as `cmd baz --foo=bar`?
|
||||
- yes
|
||||
- Does the parser execute a function?
|
||||
- no
|
||||
- Does the parser execute one of several functions, depending on input?
|
||||
- no
|
||||
- Can subcommands take options that are distinct from the main command?
|
||||
- no
|
||||
- Does it output generated help when no options match?
|
||||
- no
|
||||
- Does it generated short usage? Like: `usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]`
|
||||
- no (no usage/help at all)
|
||||
- Does the user provide the long usage text? For each option? For the whole command?
|
||||
- no
|
||||
- Do subcommands (if implemented) have their own usage output?
|
||||
- no
|
||||
- Does usage print if the user runs `cmd --help`?
|
||||
- no
|
||||
- Does it set `process.exitCode`?
|
||||
- no
|
||||
- Does usage print to stderr or stdout?
|
||||
- N/A
|
||||
- Does it check types? (Say, specify that an option is a boolean, number, etc.)
|
||||
- no
|
||||
- Can an option have more than one type? (string or false, for example)
|
||||
- no
|
||||
- Can the user define a type? (Say, `type: path` to call `path.resolve()` on the argument.)
|
||||
- no
|
||||
- Does a `--foo=0o22` mean 0, 22, 18, or "0o22"?
|
||||
- `"0o22"`
|
||||
- Does it coerce types?
|
||||
- no
|
||||
- Does `--no-foo` coerce to `--foo=false`? For all options? Only boolean options?
|
||||
- no, it sets `{values:{'no-foo': true}}`
|
||||
- Is `--foo` the same as `--foo=true`? Only for known booleans? Only at the end?
|
||||
- no, they are not the same. There is no special handling of `true` as a value so it is just another string.
|
||||
- Does it read environment variables? Ie, is `FOO=1 cmd` the same as `cmd --foo=1`?
|
||||
- no
|
||||
- Do unknown arguments raise an error? Are they parsed? Are they treated as positional arguments?
|
||||
- no, they are parsed, not treated as positionals
|
||||
- Does `--` signal the end of options?
|
||||
- yes
|
||||
- Is `--` included as a positional?
|
||||
- no
|
||||
- Is `program -- foo` the same as `program foo`?
|
||||
- yes, both store `{positionals:['foo']}`
|
||||
- Does the API specify whether a `--` was present/relevant?
|
||||
- no
|
||||
- Is `-bar` the same as `--bar`?
|
||||
- no, `-bar` is a short option or options, with expansion logic that follows the
|
||||
[Utility Syntax Guidelines in POSIX.1-2017](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html). `-bar` expands to `-b`, `-a`, `-r`.
|
||||
- Is `---foo` the same as `--foo`?
|
||||
- no
|
||||
- the first is a long option named `'-foo'`
|
||||
- the second is a long option named `'foo'`
|
||||
- Is `-` a positional? ie, `bash some-test.sh | tap -`
|
||||
- yes
|
||||
|
||||
## Links & Resources
|
||||
|
||||
* [Initial Tooling Issue](https://github.com/nodejs/tooling/issues/19)
|
||||
* [Initial Proposal](https://github.com/nodejs/node/pull/35015)
|
||||
* [parseArgs Proposal](https://github.com/nodejs/node/pull/42675)
|
||||
|
||||
[coverage-image]: https://img.shields.io/nycrc/pkgjs/parseargs
|
||||
[coverage-url]: https://github.com/pkgjs/parseargs/blob/main/.nycrc
|
||||
[pkgjs/parseargs]: https://github.com/pkgjs/parseargs
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
// This example shows how to understand if a default value is used or not.
|
||||
|
||||
// 1. const { parseArgs } = require('node:util'); // from node
|
||||
// 2. const { parseArgs } = require('@pkgjs/parseargs'); // from package
|
||||
const { parseArgs } = require('..'); // in repo
|
||||
|
||||
const options = {
|
||||
file: { short: 'f', type: 'string', default: 'FOO' },
|
||||
};
|
||||
|
||||
const { values, tokens } = parseArgs({ options, tokens: true });
|
||||
|
||||
const isFileDefault = !tokens.some((token) => token.kind === 'option' &&
|
||||
token.name === 'file'
|
||||
);
|
||||
|
||||
console.log(values);
|
||||
console.log(`Is the file option [${values.file}] the default value? ${isFileDefault}`);
|
||||
|
||||
// Try the following:
|
||||
// node is-default-value.js
|
||||
// node is-default-value.js -f FILE
|
||||
// node is-default-value.js --file FILE
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
// This is an example of using tokens to add a custom behaviour.
|
||||
//
|
||||
// Require the use of `=` for long options and values by blocking
|
||||
// the use of space separated values.
|
||||
// So allow `--foo=bar`, and not allow `--foo bar`.
|
||||
//
|
||||
// Note: this is not a common behaviour, most CLIs allow both forms.
|
||||
|
||||
// 1. const { parseArgs } = require('node:util'); // from node
|
||||
// 2. const { parseArgs } = require('@pkgjs/parseargs'); // from package
|
||||
const { parseArgs } = require('..'); // in repo
|
||||
|
||||
const options = {
|
||||
file: { short: 'f', type: 'string' },
|
||||
log: { type: 'string' },
|
||||
};
|
||||
|
||||
const { values, tokens } = parseArgs({ options, tokens: true });
|
||||
|
||||
const badToken = tokens.find((token) => token.kind === 'option' &&
|
||||
token.value != null &&
|
||||
token.rawName.startsWith('--') &&
|
||||
!token.inlineValue
|
||||
);
|
||||
if (badToken) {
|
||||
throw new Error(`Option value for '${badToken.rawName}' must be inline, like '${badToken.rawName}=VALUE'`);
|
||||
}
|
||||
|
||||
console.log(values);
|
||||
|
||||
// Try the following:
|
||||
// node limit-long-syntax.js -f FILE --log=LOG
|
||||
// node limit-long-syntax.js --file FILE
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
// This example is used in the documentation.
|
||||
|
||||
// How might I add my own support for --no-foo?
|
||||
|
||||
// 1. const { parseArgs } = require('node:util'); // from node
|
||||
// 2. const { parseArgs } = require('@pkgjs/parseargs'); // from package
|
||||
const { parseArgs } = require('..'); // in repo
|
||||
|
||||
const options = {
|
||||
'color': { type: 'boolean' },
|
||||
'no-color': { type: 'boolean' },
|
||||
'logfile': { type: 'string' },
|
||||
'no-logfile': { type: 'boolean' },
|
||||
};
|
||||
const { values, tokens } = parseArgs({ options, tokens: true });
|
||||
|
||||
// Reprocess the option tokens and overwrite the returned values.
|
||||
tokens
|
||||
.filter((token) => token.kind === 'option')
|
||||
.forEach((token) => {
|
||||
if (token.name.startsWith('no-')) {
|
||||
// Store foo:false for --no-foo
|
||||
const positiveName = token.name.slice(3);
|
||||
values[positiveName] = false;
|
||||
delete values[token.name];
|
||||
} else {
|
||||
// Resave value so last one wins if both --foo and --no-foo.
|
||||
values[token.name] = token.value ?? true;
|
||||
}
|
||||
});
|
||||
|
||||
const color = values.color;
|
||||
const logfile = values.logfile ?? 'default.log';
|
||||
|
||||
console.log({ logfile, color });
|
||||
|
||||
// Try the following:
|
||||
// node negate.js
|
||||
// node negate.js --no-logfile --no-color
|
||||
// negate.js --logfile=test.log --color
|
||||
// node negate.js --no-logfile --logfile=test.log --color --no-color
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user