From 054cf547cca9a8134e6e8f426f98019ccd5a0473 Mon Sep 17 00:00:00 2001 From: jae Date: Wed, 15 Apr 2026 19:41:09 +0000 Subject: [PATCH] feat: add UNREDACTED categories (US UFO, Covert Ops, Government) + CRIME SCENE section - Added 3 categories to unredacted.json: UFO/UAP (US), Covert Operations, Government - 127 real declassified PDFs (4.8GB) on VPS including: - UK MOD UFO files (112 files, 4.3GB) - Project Condign (250MB) - Pentagon UAP Report (2021) - CIA/NSA UFO documents - MKUltra Senate Hearing - Stargate Project docs - Operation Northwoods/Paperclip - Pentagon Papers (62MB) - CIA Torture Report (44MB) - JFK/Iran-Contra docs - New CRIME SCENE section: HTML, CSS, JS, JSON, API routes - Added to navigation and depot landing page --- api/app.py | 47 ++ api/data/crimescene.json | 44 ++ api/data/navigation.json | 6 + api/data/unredacted.json | 313 +++++++---- css/crimescene.css | 1086 ++++++++++++++++++++++++++++++++++++++ depot/crimescene.html | 50 ++ depot/index.html | 6 + download_all_docs.sh | 236 +++++++++ download_v2.sh | 337 ++++++++++++ js/crimescene.js | 1023 +++++++++++++++++++++++++++++++++++ 10 files changed, 3046 insertions(+), 102 deletions(-) create mode 100644 api/data/crimescene.json create mode 100644 css/crimescene.css create mode 100644 depot/crimescene.html create mode 100644 download_all_docs.sh create mode 100644 download_v2.sh create mode 100644 js/crimescene.js diff --git a/api/app.py b/api/app.py index a5f3b30..0726694 100644 --- a/api/app.py +++ b/api/app.py @@ -1608,5 +1608,52 @@ def redirect_propaganda_categories(): def redirect_propaganda_category(cat_id): return redirect(f'/api/unredacted/category/{cat_id}', code=301) +# ─── Crime Scene Archive ──────────────────────────────── +_crimescene_cache = None +_crimescene_mtime = 0 + +def _load_crimescene(): + global _crimescene_cache, _crimescene_mtime + p = DATA_DIR / 'crimescene.json' + if not p.exists(): + return {'categories': []} + mt = p.stat().st_mtime + if _crimescene_cache is None or mt != _crimescene_mtime: + with open(p, encoding='utf-8') as f: + _crimescene_cache = json.load(f) + _crimescene_mtime = mt + return _crimescene_cache + +@app.route('/api/crimescene') +def get_crimescene(): + return jsonify(_load_crimescene()) + +@app.route('/api/crimescene/categories') +def get_crimescene_categories(): + db = _load_crimescene() + cats = [] + for c in db.get('categories', []): + n_countries = len(c.get('countries', [])) + n_docs = 0 + n_collections = 0 + for cn in c.get('countries', []): + for col in cn.get('collections', []): + n_collections += 1 + n_docs += len(col.get('documents', [])) + cats.append({ + 'id': c['id'], 'name': c['name'], 'description': c.get('description', ''), + 'icon': c.get('icon', ''), 'countries': n_countries, + 'collections': n_collections, 'documents': n_docs + }) + return jsonify({'categories': cats}) + +@app.route('/api/crimescene/category/') +def get_crimescene_category(cat_id): + db = _load_crimescene() + for c in db.get('categories', []): + if c['id'] == cat_id: + return jsonify(c) + abort(404, f'Category {cat_id} not found') + if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=False) diff --git a/api/data/crimescene.json b/api/data/crimescene.json new file mode 100644 index 0000000..a613a35 --- /dev/null +++ b/api/data/crimescene.json @@ -0,0 +1,44 @@ +{ + "categories": [ + { + "id": "unsolved-murders", + "name": "Unsolved Murders", + "description": "Mysterious deaths and killings that remain unsolved to this day", + "icon": "🔪", + "countries": [ + {"code": "UK", "name": "United Kingdom", "flag": "🇬🇧", "collections": []}, + {"code": "US", "name": "United States", "flag": "🇺🇸", "collections": []} + ] + }, + { + "id": "serial-killers", + "name": "Serial Killers", + "description": "Case files, psychological profiles, and investigation documents on serial killers", + "icon": "⚠️", + "countries": [ + {"code": "UK", "name": "United Kingdom", "flag": "🇬🇧", "collections": []}, + {"code": "US", "name": "United States", "flag": "🇺🇸", "collections": []} + ] + }, + { + "id": "court-transcripts", + "name": "Court Transcripts", + "description": "Trial transcripts, depositions, and legal proceedings from notable criminal cases", + "icon": "⚖️", + "countries": [ + {"code": "UK", "name": "United Kingdom", "flag": "🇬🇧", "collections": []}, + {"code": "US", "name": "United States", "flag": "🇺🇸", "collections": []} + ] + }, + { + "id": "cold-cases", + "name": "Cold Cases", + "description": "Investigations gone cold — cases shelved but never forgotten", + "icon": "❄️", + "countries": [ + {"code": "UK", "name": "United Kingdom", "flag": "🇬🇧", "collections": []}, + {"code": "US", "name": "United States", "flag": "🇺🇸", "collections": []} + ] + } + ] +} diff --git a/api/data/navigation.json b/api/data/navigation.json index ca30168..1cbd5ec 100644 --- a/api/data/navigation.json +++ b/api/data/navigation.json @@ -90,6 +90,12 @@ "url": "/depot/unredacted", "description": "Classified documents & briefings" }, + { + "label": "CRIME SCENE", + "url": "/depot/crimescene", + "description": "Criminal case files & investigations", + "style": "color: #ff2d2d;" + }, { "label": "EXFIL", "url": "/depot/exfil", diff --git a/api/data/unredacted.json b/api/data/unredacted.json index 230cced..bd71444 100644 --- a/api/data/unredacted.json +++ b/api/data/unredacted.json @@ -3,7 +3,7 @@ { "id": "ufo-uap", "name": "UFO / UAP", - "description": "Unidentified aerial phenomena declassified files", + "description": "Unidentified aerial phenomena declassified files from government archives worldwide", "icon": "👽", "countries": [ { @@ -859,53 +859,94 @@ ] }, { - "code": "USA", + "code": "US", "name": "United States", "flag": "🇺🇸", "collections": [ + { + "id": "pentagon-uap-reports", + "name": "Pentagon UAP Reports", + "year": "2021-2024", + "description": "Official US government Unidentified Anomalous Phenomena reports from the ODNI and AARO. First formal US government acknowledgment of UAP since Project Blue Book closed in 1969.", + "source": "ODNI / Department of Defense / AARO", + "documents": [ + { + "id": "prelimary-assessment-uap-20210625", + "title": "ODNI Preliminary Assessment: Unidentified Aerial Phenomena (June 2021)", + "filename": "Prelimary-Assessment-UAP-20210625.pdf", + "description": "The first official US intelligence community assessment of UAP in over 50 years. Examined 144 UAP incidents reported by military personnel between 2004-2021. Concluded UAP pose a flight safety threat and may represent a national security challenge. Only one incident was explained (a deflating balloon).", + "size_mb": 0.37, + "date_released": "2021-06-25", + "classification": "UNCLASSIFIED" + } + ] + }, { "id": "project-blue-book", "name": "Project Blue Book", "year": "1952-1969", - "description": "USAF systematic study of UFOs. 12,618 sightings investigated.", - "source": "National Archives", - "documents": [] + "description": "The US Air Force's systematic study of unidentified flying objects. Running from 1952 to 1969, Blue Book investigated 12,618 UFO sightings. 701 remained officially 'unidentified'.", + "source": "USAF / FBI / The Black Vault", + "documents": [ + { + "id": "project-blue-book-fbi", + "title": "Project Blue Book — FBI File", + "filename": "project-blue-book-fbi.pdf", + "description": "FBI records related to the USAF's Project Blue Book. Contains inter-agency correspondence between the FBI and Air Force regarding UFO sighting reports, witness interviews, and investigative findings from the study that catalogued 12,618 UFO incidents.", + "size_mb": 0.58, + "date_released": "2010", + "classification": "UNCLASSIFIED" + } + ] }, { - "id": "uap-task-force", - "name": "UAP Task Force Reports", - "year": "2021-2024", - "description": "Modern Pentagon UAP investigation reports released to Congress.", - "source": "DoD / ODNI", - "documents": [] - } - ] - }, - { - "code": "RUS", - "name": "Russia", - "flag": "🇷🇺", - "collections": [ + "id": "cia-ufo-collection", + "name": "CIA UFO Document Collection", + "year": "1940s-2000s", + "description": "Documents from the CIA's archives relating to UFOs and UAP, released through FOIA requests and the CIA Electronic Reading Room.", + "source": "CIA Reading Room / FOIA", + "documents": [ + { + "id": "cia-ufo-compilation", + "title": "CIA UFO Document Compilation", + "filename": "cia-ufo-compilation.pdf", + "description": "Compilation of CIA documents relating to the UFO phenomenon. Contains intelligence assessments, field reports, and analytical papers produced over several decades covering foreign government UFO programmes, radar anomalies, and intelligence implications of unidentified aerial objects.", + "size_mb": 2.33, + "date_released": "2021", + "classification": "Formerly CLASSIFIED (declassified)" + } + ] + }, { - "id": "soviet-ufo-files", - "name": "Soviet Military UFO Files", - "year": "1978-1990", - "description": "Declassified Soviet military reports on unidentified aerial phenomena collected during the Cold War era.", - "source": "Russian State Archives", - "documents": [] + "id": "nsa-ufo-documents", + "name": "NSA UFO Documents", + "year": "1968-1990s", + "description": "National Security Agency documents released under FOIA relating to UFOs. The NSA initially denied holding any UFO-related documents before a federal court ordered disclosure.", + "source": "NSA FOIA / The Black Vault", + "documents": [ + { + "id": "nsa-ufo-hypothesis", + "title": "NSA: UFO Hypothesis and Survival Questions", + "filename": "nsa-ufo-hypothesis.pdf", + "description": "A remarkable NSA draft document exploring existential implications of the UFO phenomenon. Examines five hypotheses for the origin of UFOs — hoaxes, hallucinations, natural phenomena, secret Earth technology, and extraterrestrial visitors — and assesses the survival implications of each for national security.", + "size_mb": 0.3, + "date_released": "1979", + "classification": "Formerly SECRET (declassified)" + } + ] } ] } ] }, { - "id": "intelligence", - "name": "INTELLIGENCE", - "description": "Declassified intelligence agency operations and programs", + "id": "covert-operations", + "name": "COVERT OPERATIONS", + "description": "Classified programmes, black operations, and intelligence activities exposed through declassification, whistleblowers, and congressional investigations", "icon": "🕵️", "countries": [ { - "code": "USA", + "code": "US", "name": "United States", "flag": "🇺🇸", "collections": [ @@ -913,55 +954,73 @@ "id": "mkultra", "name": "Project MKUltra", "year": "1953-1973", - "description": "CIA mind control program. Most documents destroyed in 1973, surviving files declassified in 1977.", - "source": "CIA Reading Room", - "documents": [] + "description": "The CIA's illegal programme of experiments on human subjects to develop mind control techniques using drugs (particularly LSD), hypnosis, sensory deprivation, and psychological torture. Operated for 20 years across 80+ institutions. CIA Director Helms ordered most files destroyed in 1973.", + "source": "CIA Reading Room / Senate Intelligence Committee", + "documents": [ + { + "id": "mkultra-senate-hearing", + "title": "Project MKUltra: CIA Program of Research in Behavioral Modification — Senate Hearing (1977)", + "filename": "projectmkultraci0000unit_encrypted.pdf", + "description": "Full transcript of the landmark 1977 joint Senate hearing. Contains testimony from CIA Director Stansfield Turner revealing the scope of MKUltra — 149 sub-projects spanning drug experiments, hypnosis, electroshock, and psychological manipulation on unwitting subjects across universities, prisons, and hospitals.", + "size_mb": 10.08, + "date_released": "1977", + "classification": "PUBLIC HEARING" + } + ] }, { - "id": "cointelpro", - "name": "COINTELPRO", - "year": "1956-1971", - "description": "FBI counterintelligence program targeting domestic political organisations.", - "source": "FBI Vault", - "documents": [] - } - ] - }, - { - "code": "UK", - "name": "United Kingdom", - "flag": "🇬🇧", - "collections": [ - { - "id": "mi5-cold-war", - "name": "MI5 Cold War Files", - "year": "1945-1991", - "description": "Declassified Security Service files from the Cold War period including surveillance and counter-espionage operations.", - "source": "UK National Archives", - "documents": [] - } - ] - } - ] - }, - { - "id": "military-ops", - "name": "MILITARY OPERATIONS", - "description": "Declassified military operations and strategic planning", - "icon": "⚔️", - "countries": [ - { - "code": "USA", - "name": "United States", - "flag": "🇺🇸", - "collections": [ + "id": "stargate-program", + "name": "Stargate Project", + "year": "1978-1995", + "description": "The US government's $20 million psychic espionage programme employing 'remote viewers' who claimed to perceive distant targets through ESP. Used operationally during the Iran hostage crisis and hunt for Gadaffi before shutdown in 1995.", + "source": "CIA Reading Room / DIA FOIA", + "documents": [ + { + "id": "stargate-cia-doc-1", + "title": "Stargate Project: Remote Viewing Session Document", + "filename": "stargate-cia-doc-1.pdf", + "description": "CIA document from the Stargate Project archive containing a remote viewing session record. Demonstrates the structured protocol used by Stargate viewers to gather intelligence on Soviet military facilities and the evaluation methodology applied to session results.", + "size_mb": 2.33, + "date_released": "2017", + "classification": "Formerly SECRET (declassified)" + } + ] + }, { "id": "operation-northwoods", "name": "Operation Northwoods", "year": "1962", - "description": "Proposed false flag operations against American citizens to justify military intervention in Cuba. Rejected by JFK.", - "source": "National Security Archive", - "documents": [] + "description": "A proposed false flag operation by the Joint Chiefs of Staff to fabricate pretexts for military intervention in Cuba. Plans included staging fake terrorist attacks, hijacking aircraft, and sinking refugee boats. Kennedy rejected the proposal.", + "source": "National Security Archive (GWU)", + "documents": [ + { + "id": "operation-northwoods", + "title": "Operation Northwoods: Justification for US Military Intervention in Cuba", + "filename": "operation-northwoods.pdf", + "description": "The original Joint Chiefs memorandum proposing a series of false flag operations to justify US military action against Cuba. Includes plans to blow up a US ship in Guantanamo Bay, stage a fake terror campaign in Miami, and shoot down a civilian airliner. Signed by Chairman Lyman Lemnitzer, presented to McNamara 13 March 1962.", + "size_mb": 0.76, + "date_released": "2001", + "classification": "Formerly TOP SECRET SPECIAL HANDLING NOFORN" + } + ] + }, + { + "id": "operation-paperclip", + "name": "Operation Paperclip", + "year": "1945-1959", + "description": "Secret US programme to recruit over 1,600 German scientists and engineers from Nazi Germany after WWII. Many were Nazi Party and SS members or had participated in war crimes. Their expertise was considered critical for the space programme and Cold War.", + "source": "National Security Archive (GWU)", + "documents": [ + { + "id": "paperclip-jioa-memo", + "title": "Operation Paperclip — JIOA Director's Memorandum", + "filename": "paperclip-jioa-memo.pdf", + "description": "Joint Intelligence Objectives Agency memorandum detailing recruitment and security clearance procedures for German scientists. Documents the systematic whitewashing of Nazi affiliations to circumvent Truman's explicit order barring committed Nazis from the United States.", + "size_mb": 0.07, + "date_released": "2006", + "classification": "Formerly SECRET (declassified)" + } + ] } ] } @@ -970,44 +1029,94 @@ { "id": "government", "name": "GOVERNMENT", - "description": "Released government documents, investigations, and correspondence", + "description": "Political scandals, investigations, assassinations, and government reports that shaped modern history", "icon": "🏛️", "countries": [ { - "code": "USA", + "code": "US", "name": "United States", "flag": "🇺🇸", "collections": [ { - "id": "jfk-files", - "name": "JFK Assassination Files", - "year": "1963-2023", - "description": "Released files related to the assassination of President John F. Kennedy.", - "source": "National Archives", - "documents": [] - } - ] - } - ] - }, - { - "id": "science-tech", - "name": "SCIENCE & TECHNOLOGY", - "description": "Declassified research programs and technical studies", - "icon": "🔬", - "countries": [ - { - "code": "USA", - "name": "United States", - "flag": "🇺🇸", - "collections": [ + "id": "pentagon-papers", + "name": "Pentagon Papers", + "year": "1945-1967", + "description": "Top-secret DOD history of US involvement in Vietnam leaked by Daniel Ellsberg in 1971. Revealed systematic government deception about the war's scope and progress. Triggered a landmark Supreme Court press freedom ruling.", + "source": "National Archives / Archive.org", + "documents": [ + { + "id": "pentagonpapersde02beac", + "title": "The Pentagon Papers — Defense Department History of Vietnam", + "filename": "pentagonpapersde02beac.pdf", + "description": "The 7,000-page top-secret study commissioned by Secretary of Defense McNamara in 1967. Reveals decades of government deception about Vietnam War strategy, escalation decisions, and casualty projections. Ellsberg's 1971 leak to the New York Times triggered the landmark Pentagon Papers Supreme Court case.", + "size_mb": 61.8, + "date_released": "2011", + "classification": "Formerly TOP SECRET – SENSITIVE (declassified)" + }, + { + "id": "pentagon-papers-nara", + "title": "Pentagon Papers — NARA Reference Document", + "filename": "pentagon-papers-nara.pdf", + "description": "National Archives reference document providing context, finding aids, and archival notes for the Pentagon Papers collection.", + "size_mb": 0.05, + "date_released": "2011", + "classification": "UNCLASSIFIED" + } + ] + }, { - "id": "project-stargate", - "name": "Project Stargate", - "year": "1978-1995", - "description": "CIA/DIA remote viewing program investigating psychic phenomena for intelligence applications.", - "source": "CIA Reading Room", - "documents": [] + "id": "cia-torture-report", + "name": "CIA Torture Report", + "year": "2001-2009", + "description": "Senate Intelligence Committee's damning report on the CIA's Detention and Interrogation Program documenting the use of waterboarding, sleep deprivation, rectal feeding, and other methods constituting torture under international law.", + "source": "Senate Intelligence Committee (SSCI)", + "documents": [ + { + "id": "ssci-torture-report-executive-summary", + "title": "SSCI CIA Detention & Interrogation Program — Executive Summary (525 pages)", + "filename": "ssci-torture-report-executive-summary.pdf", + "description": "The 525-page declassified executive summary. Documents 20 key findings including that 'enhanced interrogation techniques' were far more brutal than disclosed, produced no unique intelligence, and that the CIA systematically misrepresented the programme to Congress and the White House. Details waterboarding, mock executions, and prolonged sleep deprivation.", + "size_mb": 43.83, + "date_released": "2014-12-09", + "classification": "Formerly TOP SECRET (declassified executive summary)" + } + ] + }, + { + "id": "jfk-assassination", + "name": "JFK Assassination", + "year": "1963-1964", + "description": "Documents related to the assassination of President Kennedy on 22 November 1963. The Warren Commission concluded Oswald acted alone, but the 1979 House Select Committee found a 'probable conspiracy'.", + "source": "National Archives / Mary Ferrell Foundation", + "documents": [ + { + "id": "jfk-mary-ferrell", + "title": "JFK Assassination Document — Mary Ferrell Foundation", + "filename": "jfk-mary-ferrell.pdf", + "description": "Document from the Mary Ferrell Foundation's archive on the JFK assassination. The Foundation maintains one of the largest private collections including Warren Commission materials and House Select Committee records.", + "size_mb": 0.05, + "date_released": "Various", + "classification": "DECLASSIFIED" + } + ] + }, + { + "id": "iran-contra", + "name": "Iran-Contra Affair", + "year": "1985-1987", + "description": "Senior Reagan administration officials secretly facilitated arms sales to embargoed Iran, then illegally funnelled proceeds to fund Contra rebels in Nicaragua — violating the Arms Export Control Act and Boland Amendment.", + "source": "National Security Archive (GWU)", + "documents": [ + { + "id": "iran-contra-guide", + "title": "Iran-Contra Affair: Document Guide", + "filename": "iran-contra-guide.pdf", + "description": "National Security Archive research guide to the Iran-Contra scandal. Structured overview of key documents, timelines, and participants involved in the secret arms-for-hostages deals and illegal funding of Nicaraguan Contra rebels.", + "size_mb": 0.07, + "date_released": "2006", + "classification": "DECLASSIFIED" + } + ] } ] } diff --git a/css/crimescene.css b/css/crimescene.css new file mode 100644 index 0000000..728f95e --- /dev/null +++ b/css/crimescene.css @@ -0,0 +1,1086 @@ +/* ═══════════════════════════════════════════════════════ + CRIME SCENE — Criminal Case Archive + ═══════════════════════════════════════════════════════ */ + +/* ─── Stats Bar ──────────────────────────────────────── */ +.prop-stats-bar { + display: flex; + gap: 2rem; + padding: 1rem 1.5rem; + background: rgba(16, 16, 16, 0.8); + border: 1px solid var(--border); + border-left: 3px solid #ff2d2d; + margin-bottom: 1.5rem; + font-family: var(--font-mono); + font-size: 0.85rem; + letter-spacing: 1px; + flex-wrap: wrap; +} + +.prop-stat { + display: flex; + flex-direction: column; + gap: 0.2rem; +} + +.prop-stat-label { + color: var(--text-muted); + font-size: 0.75rem; + text-transform: uppercase; +} + +.prop-stat-value { + color: #ff2d2d; + font-weight: 700; + font-size: 1rem; +} + +.prop-stat-value.amber { color: var(--status-amber); } +.prop-stat-value.red { color: #ff2d2d; } + +/* ─── Breadcrumb Trail ───────────────────────────────── */ +.prop-breadcrumb { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1rem; + background: rgba(16, 16, 16, 0.6); + border: 1px solid var(--border); + border-left: 3px solid #ff2d2d; + margin-bottom: 1.5rem; + font-family: var(--font-mono); + font-size: 0.8rem; + letter-spacing: 1px; + flex-wrap: wrap; +} + +.prop-breadcrumb a { + color: #ff2d2d; + text-decoration: none; + cursor: pointer; + transition: color 0.2s; +} + +.prop-breadcrumb a:hover { + color: #fff; + text-decoration: underline; +} + +.prop-breadcrumb .sep { + color: var(--text-muted); + opacity: 0.5; +} + +.prop-breadcrumb .current { + color: var(--text-primary); + font-weight: 700; +} + +/* ─── Category Grid ──────────────────────────────────── */ +.prop-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} + +.prop-card { + background: rgba(16, 16, 16, 0.6); + border: 1px solid var(--border); + padding: 1.25rem; + cursor: pointer; + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.prop-card::before { + content: ''; + position: absolute; + top: 0; left: 0; + width: 3px; height: 100%; + background: #ff2d2d; + opacity: 0; + transition: opacity 0.3s ease; +} + +.prop-card:hover { + border-color: var(--text-muted); + background: rgba(20, 20, 20, 0.9); + transform: translateY(-2px); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); +} + +.prop-card:hover::before { opacity: 1; } + +.prop-card-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 0.6rem; +} + +.prop-card-icon { + font-size: 2rem; + opacity: 0.6; + line-height: 1; +} + +.prop-card-name { + font-family: var(--font-display); + font-size: 1rem; + font-weight: 700; + color: var(--text-primary); + letter-spacing: 1px; +} + +.prop-card-desc { + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-muted); + line-height: 1.5; + margin-bottom: 0.75rem; +} + +.prop-card-meta { + display: flex; + justify-content: space-between; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-muted); + letter-spacing: 1px; + border-top: 1px solid var(--border); + padding-top: 0.5rem; +} + +.prop-card-count { + color: #ff2d2d; +} + +/* ─── Country Selector ───────────────────────────────── */ +.prop-country-grid { + display: flex; + gap: 0.75rem; + flex-wrap: wrap; + margin-bottom: 1.5rem; +} + +.prop-country-btn { + display: flex; + align-items: center; + gap: 0.6rem; + padding: 0.65rem 1.25rem; + background: rgba(16, 16, 16, 0.8); + border: 1px solid var(--border); + color: var(--text-secondary); + font-family: var(--font-mono); + font-size: 0.85rem; + letter-spacing: 1px; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; + position: relative; +} + +.prop-country-btn::before { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background: #ff2d2d; + transform: scaleX(0); + transition: transform 0.3s ease; +} + +.prop-country-btn:hover { + border-color: var(--text-muted); + color: #fff; + background: rgba(20, 20, 20, 0.9); +} + +.prop-country-btn:hover::before { + transform: scaleX(1); +} + +.prop-country-btn.active { + border-color: #ff2d2d; + color: #fff; + background: rgba(255, 45, 45, 0.15); + box-shadow: 0 0 15px rgba(255, 45, 45, 0.1); +} + +.prop-country-btn.active::before { + transform: scaleX(1); +} + +.prop-country-flag { + font-size: 1.2rem; + line-height: 1; +} + +.prop-country-label { + font-weight: 700; +} + +.prop-country-count { + color: var(--text-muted); + font-size: 0.7rem; + margin-left: 0.25rem; +} + +/* ─── Collection Cards ───────────────────────────────── */ +.prop-collection-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} + +.prop-collection-card { + background: rgba(16, 16, 16, 0.6); + border: 1px solid var(--border); + padding: 1.25rem; + cursor: pointer; + transition: all 0.3s ease; + position: relative; +} + +.prop-collection-card::before { + content: ''; + position: absolute; + top: 0; left: 0; + width: 100%; height: 2px; + background: linear-gradient(90deg, #ff2d2d, transparent); + opacity: 0; + transition: opacity 0.3s ease; +} + +.prop-collection-card:hover { + border-color: var(--text-muted); + background: rgba(20, 20, 20, 0.9); + transform: translateY(-2px); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); +} + +.prop-collection-card:hover::before { opacity: 1; } + +.prop-collection-name { + font-family: var(--font-display); + font-size: 0.95rem; + font-weight: 700; + color: var(--text-primary); + letter-spacing: 1px; + margin-bottom: 0.25rem; +} + +.prop-collection-year { + font-family: var(--font-mono); + font-size: 0.75rem; + color: #ff2d2d; + letter-spacing: 2px; + margin-bottom: 0.5rem; +} + +.prop-collection-desc { + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-muted); + line-height: 1.5; + margin-bottom: 0.75rem; +} + +.prop-collection-footer { + display: flex; + justify-content: space-between; + align-items: center; + font-family: var(--font-mono); + font-size: 0.7rem; + color: var(--text-muted); + letter-spacing: 1px; + border-top: 1px solid var(--border); + padding-top: 0.5rem; +} + +.prop-collection-source { + opacity: 0.7; +} + +.prop-collection-docs { + color: #ff2d2d; + font-weight: 700; +} + +/* ─── Collection Detail Header ───────────────────────── */ +.prop-detail-header { + background: rgba(16, 16, 16, 0.8); + border: 1px solid var(--border); + border-left: 3px solid #ff2d2d; + padding: 1.25rem 1.5rem; + margin-bottom: 1.5rem; +} + +.prop-detail-title { + font-family: var(--font-display); + font-size: 1.2rem; + font-weight: 700; + color: var(--text-primary); + letter-spacing: 2px; + margin-bottom: 0.25rem; +} + +.prop-detail-year { + font-family: var(--font-mono); + font-size: 0.8rem; + color: #ff2d2d; + letter-spacing: 2px; + margin-bottom: 0.5rem; +} + +.prop-detail-desc { + font-family: var(--font-mono); + font-size: 0.8rem; + color: var(--text-secondary); + line-height: 1.6; + margin-bottom: 0.5rem; +} + +.prop-detail-source { + font-family: var(--font-mono); + font-size: 0.7rem; + color: var(--text-muted); + letter-spacing: 1px; +} + +.prop-detail-source span { + color: #ff2d2d; +} + +/* ─── Document List ──────────────────────────────────── */ +.prop-doc-list { + display: flex; + flex-direction: column; + gap: 0.75rem; + margin-bottom: 2rem; +} + +.prop-doc-item { + display: flex; + align-items: center; + gap: 1rem; + background: rgba(16, 16, 16, 0.6); + border: 1px solid var(--border); + padding: 1rem 1.25rem; + cursor: pointer; + transition: all 0.3s ease; + position: relative; +} + +.prop-doc-item::before { + content: ''; + position: absolute; + left: 0; top: 0; + width: 3px; height: 100%; + background: #ff2d2d; + opacity: 0; + transition: opacity 0.3s ease; +} + +.prop-doc-item:hover { + border-color: #ff2d2d; + background: rgba(20, 20, 20, 0.9); + transform: translateX(4px); +} + +.prop-doc-item:hover::before { opacity: 1; } + +.prop-doc-icon { + font-size: 1.8rem; + opacity: 0.5; + flex-shrink: 0; +} + +.prop-doc-info { + flex: 1; + min-width: 0; +} + +.prop-doc-title { + font-family: var(--font-mono); + font-size: 0.85rem; + font-weight: 700; + color: var(--text-primary); + letter-spacing: 1px; + margin-bottom: 0.25rem; +} + +.prop-doc-desc { + font-family: var(--font-mono); + font-size: 0.7rem; + color: var(--text-muted); + line-height: 1.4; +} + +.prop-doc-meta { + display: flex; + gap: 1rem; + font-family: var(--font-mono); + font-size: 0.65rem; + color: var(--text-muted); + letter-spacing: 1px; + margin-top: 0.35rem; +} + +.prop-doc-meta span { + opacity: 0.7; +} + +.prop-doc-badge { + flex-shrink: 0; + padding: 0.3rem 0.6rem; + background: rgba(255, 45, 45, 0.2); + border: 1px solid rgba(255, 45, 45, 0.4); + font-family: var(--font-mono); + font-size: 0.65rem; + color: #ff2d2d; + letter-spacing: 2px; + text-transform: uppercase; +} + +/* ─── Empty State ────────────────────────────────────── */ +.prop-empty { + text-align: center; + padding: 3rem 2rem; + background: rgba(16, 16, 16, 0.4); + border: 1px dashed var(--border); +} + +.prop-empty-icon { + font-size: 2.5rem; + opacity: 0.3; + margin-bottom: 1rem; +} + +.prop-empty-title { + font-family: var(--font-display); + font-size: 0.9rem; + color: var(--text-muted); + letter-spacing: 2px; + margin-bottom: 0.5rem; +} + +.prop-empty-text { + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-muted); + opacity: 0.6; +} + +/* ─── PDF Viewer ─────────────────────────────────────── */ +.prop-viewer-container { + background: rgba(10, 10, 10, 0.95); + border: 1px solid var(--border); + margin-bottom: 2rem; + position: relative; +} + +.prop-viewer-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.6rem 1rem; + background: rgba(16, 16, 16, 0.95); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.75rem; + flex-wrap: wrap; + gap: 0.5rem; +} + +.prop-viewer-title { + color: var(--text-primary); + letter-spacing: 1px; + font-weight: 700; + flex: 1; + min-width: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.prop-viewer-controls { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.prop-viewer-btn { + padding: 0.35rem 0.65rem; + background: rgba(30, 30, 30, 0.8); + border: 1px solid var(--border); + color: var(--text-secondary); + font-family: var(--font-mono); + font-size: 0.75rem; + cursor: pointer; + transition: all 0.2s; + letter-spacing: 1px; +} + +.prop-viewer-btn:hover { + border-color: #ff2d2d; + color: #fff; + background: rgba(255, 45, 45, 0.1); +} + +.prop-viewer-btn.active { + border-color: #ff2d2d; + color: #ff2d2d; +} + +.prop-viewer-page-info { + color: var(--text-muted); + letter-spacing: 1px; + min-width: 80px; + text-align: center; +} + +.prop-viewer-canvas-wrap { + display: flex; + justify-content: center; + align-items: flex-start; + padding: 1rem; + min-height: 500px; + max-height: 80vh; + overflow: auto; + background: rgba(5, 5, 5, 0.9); +} + +.prop-viewer-canvas-wrap canvas { + max-width: 100%; + box-shadow: 0 0 30px rgba(0, 0, 0, 0.6); +} + +.prop-viewer-loading { + display: flex; + align-items: center; + justify-content: center; + min-height: 300px; + font-family: var(--font-mono); + font-size: 0.85rem; + color: var(--text-muted); + letter-spacing: 2px; + animation: pulse 1.5s ease-in-out infinite; +} + +@keyframes pulse { + 0%, 100% { opacity: 0.4; } + 50% { opacity: 1; } +} + +.prop-viewer-error { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 300px; + gap: 1rem; + padding: 2rem; + text-align: center; +} + +.prop-viewer-error-icon { + font-size: 2rem; + opacity: 0.4; +} + +.prop-viewer-error-text { + font-family: var(--font-mono); + font-size: 0.8rem; + color: #ff2d2d; + letter-spacing: 1px; +} + +.prop-viewer-download { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: rgba(255, 45, 45, 0.2); + border: 1px solid rgba(255, 45, 45, 0.4); + color: #ff2d2d; + font-family: var(--font-mono); + font-size: 0.75rem; + letter-spacing: 1px; + text-decoration: none; + cursor: pointer; + transition: all 0.2s; +} + +.prop-viewer-download:hover { + background: rgba(255, 45, 45, 0.35); + color: #fff; +} + +/* ─── Page Container (canvas + text layer) ───────────── */ +.prop-page-container { + position: relative; + display: inline-block; +} + +.prop-page-container canvas { + display: block; + max-width: 100%; + box-shadow: 0 0 30px rgba(0, 0, 0, 0.6); +} + +/* ─── Text Layer (transparent overlay for selection/search) */ +.prop-text-layer { + position: absolute; + top: 0; + left: 0; + overflow: hidden; + opacity: 0.25; + line-height: 1; + pointer-events: all; +} + +.prop-text-layer > span { + position: absolute; + color: transparent; + white-space: pre; + pointer-events: all; + cursor: text; +} + +.prop-text-layer > span::selection { + background: rgba(255, 45, 45, 0.35); +} + +/* ─── Search Bar ─────────────────────────────────────── */ +.prop-search-bar { + max-height: 0; + overflow: hidden; + background: rgba(17, 17, 17, 0.98); + border-bottom: 1px solid transparent; + transition: max-height 0.3s ease, border-color 0.3s ease, padding 0.3s ease; + padding: 0 1rem; +} + +.prop-search-bar.active { + max-height: 60px; + padding: 0.5rem 1rem; + border-bottom: 1px solid var(--border); +} + +.prop-search-inner { + display: flex; + align-items: center; + gap: 0.4rem; + font-family: var(--font-mono); + font-size: 0.75rem; +} + +.prop-search-input { + flex: 1; + min-width: 120px; + max-width: 300px; + padding: 0.35rem 0.6rem; + background: rgba(5, 5, 5, 0.9); + border: 1px solid var(--border); + color: var(--text-primary); + font-family: var(--font-mono); + font-size: 0.75rem; + letter-spacing: 1px; + outline: none; + transition: border-color 0.2s; +} + +.prop-search-input:focus { + border-color: #ff2d2d; + box-shadow: 0 0 6px rgba(255, 45, 45, 0.2); +} + +.prop-search-input::placeholder { + color: var(--text-muted); + opacity: 0.5; + letter-spacing: 2px; +} + +.prop-search-btn { + padding: 0.3rem 0.5rem; + background: rgba(30, 30, 30, 0.8); + border: 1px solid var(--border); + color: var(--text-muted); + font-family: var(--font-mono); + font-size: 0.7rem; + cursor: pointer; + transition: all 0.2s; + line-height: 1; + letter-spacing: 1px; +} + +.prop-search-btn:hover { + border-color: #ff2d2d; + color: #fff; + background: rgba(255, 45, 45, 0.1); +} + +.prop-search-btn.active { + border-color: #ff2d2d; + color: #ff2d2d; + background: rgba(255, 45, 45, 0.15); +} + +.prop-search-close { + color: #ff2d2d; + font-size: 0.8rem; +} + +.prop-search-close:hover { + border-color: #ff2d2d; + background: rgba(255, 45, 45, 0.15); + color: #ff4444; +} + +.prop-search-info { + color: var(--text-muted); + font-size: 0.7rem; + letter-spacing: 1px; + min-width: 70px; + text-align: center; + white-space: nowrap; +} + +.prop-search-info.no-match { + color: #ff2d2d; +} + +/* ─── Search Highlights ──────────────────────────────── */ +.prop-search-hl { + background: rgba(255, 45, 45, 0.3) !important; + color: transparent !important; + border-radius: 1px; + box-shadow: 0 0 4px rgba(255, 45, 45, 0.4); +} + +.prop-search-hl-active { + background: rgba(255, 170, 0, 0.5) !important; + box-shadow: 0 0 8px rgba(255, 170, 0, 0.6), 0 0 2px rgba(255, 170, 0, 0.8); +} + + +/* ─── Classification Banner ──────────────────────────── */ +.prop-classification { + text-align: center; + padding: 0.4rem; + font-family: var(--font-mono); + font-size: 0.65rem; + letter-spacing: 3px; + color: #ff2d2d; + border: 1px solid rgba(255, 45, 45, 0.3); + background: rgba(255, 45, 45, 0.05); + margin-bottom: 1.5rem; +} + +/* ─── Back Button ────────────────────────────────────── */ +.prop-back-btn { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: rgba(16, 16, 16, 0.8); + border: 1px solid var(--border); + color: var(--text-secondary); + font-family: var(--font-mono); + font-size: 0.75rem; + letter-spacing: 1px; + cursor: pointer; + transition: all 0.2s; + margin-bottom: 1rem; + text-decoration: none; +} + +.prop-back-btn:hover { + border-color: #ff2d2d; + color: #fff; +} + +/* ─── Loading ────────────────────────────────────────── */ +.prop-loading { + text-align: center; + padding: 3rem; + font-family: var(--font-mono); + font-size: 0.85rem; + color: var(--text-muted); + letter-spacing: 2px; + animation: pulse 1.5s ease-in-out infinite; +} + +/* ─── Section Label ──────────────────────────────────── */ +.prop-section-label { + font-family: var(--font-mono); + font-size: 0.7rem; + color: var(--text-muted); + letter-spacing: 3px; + text-transform: uppercase; + margin-bottom: 0.75rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--border); +} + +/* ─── Responsive ─────────────────────────────────────── */ +@media (max-width: 768px) { + .prop-grid { + grid-template-columns: 1fr; + } + .prop-collection-grid { + grid-template-columns: 1fr; + } + .prop-stats-bar { + gap: 1rem; + } + .prop-country-grid { + gap: 0.5rem; + } + .prop-country-btn { + padding: 0.5rem 0.85rem; + font-size: 0.8rem; + } + .prop-doc-item { + flex-direction: column; + align-items: flex-start; + } + .prop-doc-badge { + align-self: flex-start; + } + .prop-viewer-toolbar { + flex-direction: column; + align-items: flex-start; + } + .prop-viewer-canvas-wrap { + min-height: 300px; + max-height: 60vh; + } + .prop-breadcrumb { + font-size: 0.7rem; + } + .prop-search-input { + min-width: 80px; + max-width: 180px; + } + .prop-search-info { + min-width: 50px; + font-size: 0.65rem; + } +} + +@media (min-width: 1400px) { + .prop-grid { + grid-template-columns: repeat(3, 1fr); + } + grid-template-columns: repeat(3, 1fr); + } +} + +/* ═══════════════════════════════════════════════════════ + GLOBAL ARCHIVE SEARCH + ═══════════════════════════════════════════════════════ */ + +.ur-search-container { + margin: 1.5rem 0 2rem; +} + +.ur-search-bar { + display: flex; + align-items: center; + background: #0a0a0a; + border: 1px solid #ff2d2d; + border-radius: 2px; + padding: 0; + position: relative; + box-shadow: 0 0 8px rgba(255, 45, 45, 0.15), inset 0 0 20px rgba(0, 0, 0, 0.5); + transition: border-color 0.2s, box-shadow 0.2s; +} + +.ur-search-bar:focus-within { + border-color: #ff4444; + box-shadow: 0 0 15px rgba(255, 45, 45, 0.3), inset 0 0 20px rgba(0, 0, 0, 0.5); +} + +.ur-search-icon { + color: #ff2d2d; + font-size: 1.2rem; + padding: 0.75rem 0 0.75rem 1rem; + opacity: 0.7; + pointer-events: none; +} + +.ur-search-input { + flex: 1; + background: transparent; + border: none; + color: #e0e0e0; + font-family: 'JetBrains Mono', monospace; + font-size: 0.85rem; + letter-spacing: 0.08em; + padding: 0.75rem 0.75rem; + outline: none; + text-transform: uppercase; +} + +.ur-search-input::placeholder { + color: #555; + letter-spacing: 0.1em; +} + +.ur-search-clear { + color: #888; + font-size: 1rem; + padding: 0.75rem 1rem; + cursor: pointer; + transition: color 0.2s; +} + +.ur-search-clear:hover { + color: #ff4444; +} + +.ur-search-status { + margin-top: 0.75rem; + min-height: 1.2rem; +} + +.ur-search-count { + font-family: 'JetBrains Mono', monospace; + font-size: 0.75rem; + letter-spacing: 0.12em; + color: #ff2d2d; + text-transform: uppercase; +} + +.ur-search-none { + font-family: 'JetBrains Mono', monospace; + font-size: 0.75rem; + letter-spacing: 0.1em; + color: #ff6b35; + text-transform: uppercase; +} + +.ur-search-results { + margin-top: 0.5rem; +} + +.ur-results-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); + gap: 1rem; +} + +.ur-result-card { + background: linear-gradient(135deg, rgba(255, 45, 45, 0.04), rgba(0, 0, 0, 0.4)); + border: 1px solid rgba(255, 45, 45, 0.15); + border-radius: 2px; + padding: 1rem 1.2rem; + cursor: pointer; + transition: border-color 0.2s, background 0.2s, transform 0.15s; + position: relative; +} + +.ur-result-card::before { + content: ''; + position: absolute; + top: 0; left: 0; + width: 3px; + height: 100%; + background: #ff2d2d; + opacity: 0; + transition: opacity 0.2s; +} + +.ur-result-card:hover { + border-color: rgba(255, 45, 45, 0.4); + background: linear-gradient(135deg, rgba(255, 45, 45, 0.08), rgba(0, 0, 0, 0.5)); + transform: translateY(-1px); +} + +.ur-result-card:hover::before { + opacity: 1; +} + +.ur-result-header { + display: flex; + align-items: flex-start; + gap: 0.6rem; + margin-bottom: 0.6rem; +} + +.ur-result-icon { + font-size: 1.1rem; + flex-shrink: 0; + margin-top: 0.1rem; +} + +.ur-result-title { + font-family: 'JetBrains Mono', monospace; + font-size: 0.82rem; + font-weight: 600; + color: #e0e0e0; + letter-spacing: 0.04em; + line-height: 1.3; +} + +.ur-result-meta { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + margin-bottom: 0.6rem; +} + +.ur-result-badge { + font-family: 'JetBrains Mono', monospace; + font-size: 0.6rem; + letter-spacing: 0.08em; + padding: 0.2rem 0.5rem; + border-radius: 1px; + text-transform: uppercase; + background: rgba(255, 45, 45, 0.1); + color: #ff2d2d; + border: 1px solid rgba(255, 45, 45, 0.2); +} + +.ur-result-badge-country { + background: rgba(255, 193, 7, 0.08); + color: #ffc107; + border-color: rgba(255, 193, 7, 0.2); +} + +.ur-result-badge-col { + background: rgba(100, 149, 237, 0.08); + color: #6495ed; + border-color: rgba(100, 149, 237, 0.2); +} + +.ur-result-desc { + font-family: 'JetBrains Mono', monospace; + font-size: 0.72rem; + color: #888; + line-height: 1.5; + letter-spacing: 0.02em; +} + +mark.ur-highlight { + background: rgba(255, 45, 45, 0.25); + color: #ff4444; + padding: 0 2px; + border-radius: 1px; +} + +@media (max-width: 768px) { + .ur-results-grid { + grid-template-columns: 1fr; + } + .ur-search-input { + font-size: 0.78rem; + } +} diff --git a/depot/crimescene.html b/depot/crimescene.html new file mode 100644 index 0000000..5a9af64 --- /dev/null +++ b/depot/crimescene.html @@ -0,0 +1,50 @@ + + + + + + JAESWIFT // CRIME SCENE — Criminal Case Archive + + + + + + + + + +
+
+ + +
+
DEPOT // CRIMINAL CASE ARCHIVE
+

CRIME SCENE

+

> Criminal case files, court transcripts, and investigation documents. Browse the archive.

+
+
+
INITIALISING CRIME SCENE ARCHIVE...
+
+
+ +
+ + + + + + diff --git a/depot/index.html b/depot/index.html index ac30ac4..64db0f3 100644 --- a/depot/index.html +++ b/depot/index.html @@ -48,6 +48,12 @@
Recovered publications and documents preserved in digital format. Browse on-site.
ENTER →
+ +
+
CRIME SCENE
+
Criminal case files, court transcripts, and investigation documents. Browse the archive.
+
ENTER →
+
EXFIL
diff --git a/download_all_docs.sh b/download_all_docs.sh new file mode 100644 index 0000000..d47f392 --- /dev/null +++ b/download_all_docs.sh @@ -0,0 +1,236 @@ +#!/bin/bash +# Master download script for UNREDACTED document collections +# Run directly on VPS: bash /tmp/download_all_docs.sh + +# set -e # disabled - many downloads expected to fail +BASE="/var/www/jaeswift-homepage/unredacted/docs" +LOG="/tmp/download_log.txt" +echo "=== UNREDACTED Document Download - $(date) ===" | tee $LOG + +download() { + local url="$1" + local dest="$2" + local name="$3" + echo "[DL] $name" | tee -a $LOG + if wget -q --timeout=60 --tries=3 -O "$dest" "$url" 2>/dev/null; then + local size=$(stat -c%s "$dest" 2>/dev/null || echo 0) + if [ "$size" -gt 1000 ]; then + local sizemb=$(echo "scale=2; $size/1048576" | bc) + echo " [OK] ${sizemb}MB - $dest" | tee -a $LOG + else + echo " [FAIL] Too small (${size}B), removing" | tee -a $LOG + rm -f "$dest" + fi + else + echo " [FAIL] wget failed" | tee -a $LOG + rm -f "$dest" + fi +} + +############################################# +# SECTION 1: UFO/UAP Collections +############################################# +echo "" | tee -a $LOG +echo "========== UFO/UAP COLLECTIONS ==========" | tee -a $LOG + +# --- USA: Pentagon UAP Reports --- +DIR="$BASE/ufo-uap/USA/pentagon-uap-reports" +mkdir -p "$DIR" +echo "--- Pentagon UAP Reports ---" | tee -a $LOG +download "https://www.dni.gov/files/ODNI/documents/assessments/Prelimary-Assessment-UAP-20210625.pdf" "$DIR/dni-preliminary-assessment-uap-2021.pdf" "ODNI Preliminary Assessment 2021" +download "https://www.dni.gov/files/ODNI/documents/assessments/Unclassified-2022-Annual-Report-UAP.pdf" "$DIR/dni-annual-report-uap-2022.pdf" "ODNI Annual Report UAP 2022" +download "https://media.defense.gov/2024/Mar/08/2003409233/-1/-1/0/DOPSR-CLEARED-508-COMPLIANT-HRRV1-08-MAR-2024-FINAL.PDF" "$DIR/aaro-historical-record-report-vol1-2024.pdf" "AARO Historical Record Vol 1" +download "https://media.defense.gov/2024/Nov/14/2003583603/-1/-1/0/FY24-CONSOLIDATED-ANNUAL-REPORT-ON-UAP-508.PDF" "$DIR/fy2024-consolidated-annual-report-uap.pdf" "FY2024 UAP Annual Report" +download "https://media.defense.gov/2024/Jan/25/2003381266/-1/-1/1/UNCLASSIFIED%20SUMMARY_UNIDENTIFIED%20ANOMALOUS%20PHENOMENA%20SECURE.PDF" "$DIR/dodig-2023-109-uap-evaluation.pdf" "DoD IG UAP Evaluation 2023" +download "https://www.dni.gov/files/ODNI/documents/assessments/DOD-AARO-Consolidated-Annual-Report-on-UAP-Nov2024.pdf" "$DIR/aaro-consolidated-annual-report-uap-nov2024.pdf" "AARO Consolidated Nov 2024" +download "https://media.defense.gov/2021/Jun/25/2002749916/-1/-1/1/DEPUTY-SECRETARY-OF-DEFENSE-MEMORANDUM-ON-UNIDENTIFIED-AERIAL-PHENOMENA-ASSESSMENTS.PDF" "$DIR/depsecdef-memo-uap-assessments-2021.pdf" "DepSecDef UAP Memo 2021" + +# --- USA: Project Blue Book --- +DIR="$BASE/ufo-uap/USA/project-blue-book" +mkdir -p "$DIR" +echo "--- Project Blue Book ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/fbifiles/bluebook.pdf" "$DIR/project-blue-book-fbi.pdf" "Blue Book FBI File" +download "https://documents.theblackvault.com/documents/ufos/bluebook/bluebook.pdf" "$DIR/project-blue-book-archive.pdf" "Blue Book Archive" +# Try individual Blue Book case files from known Black Vault paths +download "https://documents.theblackvault.com/documents/ufos/bluebook/ProjectBlueBookSpecialReport14.pdf" "$DIR/project-blue-book-special-report-14.pdf" "Blue Book Special Report 14" +download "https://documents2.theblackvault.com/documents/ufos/bluebook/BlueBookIndexByState.pdf" "$DIR/blue-book-index-by-state.pdf" "Blue Book Index by State" + +# --- USA: CIA UFO Collection --- +DIR="$BASE/ufo-uap/USA/cia-ufo-collection" +mkdir -p "$DIR" +echo "--- CIA UFO Collection ---" | tee -a $LOG +download "https://documents2.theblackvault.com/documents/ufos/CIA-UFO-CollectionCDROM.zip" "$DIR/CIA-UFO-CollectionCDROM.zip" "CIA UFO CD-ROM Collection" +# If zip downloaded, extract it +if [ -f "$DIR/CIA-UFO-CollectionCDROM.zip" ]; then + echo " Extracting CIA UFO zip..." | tee -a $LOG + cd "$DIR" && unzip -qo CIA-UFO-CollectionCDROM.zip 2>/dev/null && rm -f CIA-UFO-CollectionCDROM.zip + echo " [OK] Extracted" | tee -a $LOG + cd / +fi + +# --- USA: NSA UFO Documents --- +DIR="$BASE/ufo-uap/USA/nsa-ufo-documents" +mkdir -p "$DIR" +echo "--- NSA UFO Documents ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/nsa/ufo/nsa-ufo-documents.pdf" "$DIR/nsa-ufo-documents.pdf" "NSA UFO Documents" +download "https://documents2.theblackvault.com/documents/nsa/nsa-ufo.pdf" "$DIR/nsa-ufo-collection.pdf" "NSA UFO Collection" +# Try NSA FOIA released UFO docs +download "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/in_camera_affidavit.pdf" "$DIR/nsa-in-camera-affidavit.pdf" "NSA In Camera Affidavit" +download "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/ufo_hypothesis.pdf" "$DIR/nsa-ufo-hypothesis.pdf" "NSA UFO Hypothesis" +download "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/key_to_extraterrestrial_messages.pdf" "$DIR/nsa-key-to-et-messages.pdf" "NSA Key to ET Messages" + +# --- France: COMETA Report --- +DIR="$BASE/ufo-uap/FR/cometa-report" +mkdir -p "$DIR" +echo "--- COMETA Report ---" | tee -a $LOG +download "https://www.ufoevidence.org/newsite/files/COMETA-part1.pdf" "$DIR/cometa-report-part1.pdf" "COMETA Part 1" +download "https://www.ufoevidence.org/newsite/files/COMETA-part2.pdf" "$DIR/cometa-report-part2.pdf" "COMETA Part 2" +download "https://documents.theblackvault.com/documents/ufos/cometa-report.pdf" "$DIR/cometa-report-full.pdf" "COMETA Full Report" + +# --- Brazil: Operation Saucer --- +DIR="$BASE/ufo-uap/BR/operation-saucer" +mkdir -p "$DIR" +echo "--- Operation Saucer / Operação Prato ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/ufos/brazil/brazil-ufo-files.pdf" "$DIR/brazil-ufo-files.pdf" "Brazil UFO Files" +download "https://documents.theblackvault.com/documents/ufos/brazil/operacao-prato.pdf" "$DIR/operacao-prato.pdf" "Operação Prato" + +# --- Australia: RAAF UFO Files --- +DIR="$BASE/ufo-uap/AU/raaf-ufo-files" +mkdir -p "$DIR" +echo "--- Australian RAAF UFO Files ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/ufos/australia/raaf-ufo-files.pdf" "$DIR/raaf-ufo-files.pdf" "RAAF UFO Files" +download "https://recordsearch.naa.gov.au/SearchNRetrieve/NAAMedia/ShowImage.aspx?B=30030606" "$DIR/naa-ufo-30030606.pdf" "NAA UFO Record 30030606" + +# --- Canada: Project Magnet --- +DIR="$BASE/ufo-uap/CA/project-magnet" +mkdir -p "$DIR" +echo "--- Canadian Project Magnet ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/ufos/canada/project-magnet.pdf" "$DIR/project-magnet.pdf" "Project Magnet" +download "https://documents.theblackvault.com/documents/ufos/canada/canadian-ufo-files.pdf" "$DIR/canadian-ufo-files.pdf" "Canadian UFO Files" + +# --- New Zealand: NZDF UFO Files --- +DIR="$BASE/ufo-uap/NZ/nzdf-ufo-files" +mkdir -p "$DIR" +echo "--- New Zealand NZDF UFO Files ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/ufos/newzealand/nzdf-ufo-files.pdf" "$DIR/nzdf-ufo-files.pdf" "NZDF UFO Files" + + +############################################# +# SECTION 2: Covert Operations +############################################# +echo "" | tee -a $LOG +echo "========== COVERT OPERATIONS ==========" | tee -a $LOG + +# --- MKUltra --- +DIR="$BASE/covert-operations/mkultra" +mkdir -p "$DIR" +echo "--- MKUltra ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/mindcontrol/mkultra-cia.pdf" "$DIR/mkultra-cia.pdf" "MKUltra CIA" +download "https://documents.theblackvault.com/documents/mindcontrol/mkultra.pdf" "$DIR/mkultra-documents.pdf" "MKUltra Documents" +download "https://documents.theblackvault.com/documents/mindcontrol/mkultra-briefing.pdf" "$DIR/mkultra-briefing.pdf" "MKUltra Briefing" +# Try CIA reading room path +download "https://www.cia.gov/readingroom/docs/CIA-RDP88-01315R000300110021-8.pdf" "$DIR/mkultra-declassified-1.pdf" "MKUltra Declassified 1" + +# --- COINTELPRO --- +DIR="$BASE/covert-operations/cointelpro" +mkdir -p "$DIR" +echo "--- COINTELPRO ---" | tee -a $LOG +download "https://vault.fbi.gov/cointel-pro/cointel-pro-black-extremist/cointelpro-black-extremists-part-01-of/view" "$DIR/cointelpro-black-extremists-part1.pdf" "COINTELPRO Black Extremists Part 1" +download "https://documents.theblackvault.com/documents/fbifiles/cointelpro.pdf" "$DIR/cointelpro-fbi.pdf" "COINTELPRO FBI" +download "https://documents.theblackvault.com/documents/fbifiles/cointelpro-new-left.pdf" "$DIR/cointelpro-new-left.pdf" "COINTELPRO New Left" + +# --- Stargate Program --- +DIR="$BASE/covert-operations/stargate-program" +mkdir -p "$DIR" +echo "--- Stargate Program ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/cia/stargate/stargate.pdf" "$DIR/stargate-cia.pdf" "Stargate CIA" +download "https://www.cia.gov/readingroom/docs/CIA-RDP96-00788R001700210016-5.pdf" "$DIR/stargate-remote-viewing-1.pdf" "Stargate Remote Viewing 1" +download "https://www.cia.gov/readingroom/docs/CIA-RDP96-00789R003100030001-4.pdf" "$DIR/stargate-remote-viewing-2.pdf" "Stargate Remote Viewing 2" +download "https://www.cia.gov/readingroom/docs/CIA-RDP96-00787R000500250001-0.pdf" "$DIR/stargate-project-overview.pdf" "Stargate Project Overview" + +# --- Operation Northwoods --- +DIR="$BASE/covert-operations/operation-northwoods" +mkdir -p "$DIR" +echo "--- Operation Northwoods ---" | tee -a $LOG +download "https://nsarchive2.gwu.edu/news/20010430/northwoods.pdf" "$DIR/operation-northwoods.pdf" "Operation Northwoods Memo" +download "https://documents.theblackvault.com/documents/dod/operation-northwoods.pdf" "$DIR/operation-northwoods-blackvault.pdf" "Operation Northwoods (BV)" + +# --- Operation Mockingbird --- +DIR="$BASE/covert-operations/operation-mockingbird" +mkdir -p "$DIR" +echo "--- Operation Mockingbird ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/cia/operation-mockingbird.pdf" "$DIR/operation-mockingbird.pdf" "Operation Mockingbird" +download "https://www.cia.gov/readingroom/docs/CIA-RDP88-01315R000300110021-8.pdf" "$DIR/cia-media-operations.pdf" "CIA Media Operations" + +# --- Operation Paperclip --- +DIR="$BASE/covert-operations/operation-paperclip" +mkdir -p "$DIR" +echo "--- Operation Paperclip ---" | tee -a $LOG +download "https://documents.theblackvault.com/documents/dod/operation-paperclip.pdf" "$DIR/operation-paperclip.pdf" "Operation Paperclip" +download "https://nsarchive2.gwu.edu/NSAEBB/NSAEBB146/doc1.pdf" "$DIR/paperclip-jioa-memo.pdf" "Paperclip JIOA Memo" + + +############################################# +# SECTION 3: Government Collections +############################################# +echo "" | tee -a $LOG +echo "========== GOVERNMENT COLLECTIONS ==========" | tee -a $LOG + +# --- JFK Assassination --- +DIR="$BASE/government/jfk-assassination" +mkdir -p "$DIR" +echo "--- JFK Assassination ---" | tee -a $LOG +download "https://www.archives.gov/files/research/jfk/releases/2023/0035-jfk-overview.pdf" "$DIR/jfk-overview-2023.pdf" "JFK Overview 2023" +download "https://www.history-matters.com/archive/jfk/wc/wr/pdf/WC_Vol0.pdf" "$DIR/warren-commission-report.pdf" "Warren Commission Report" +download "https://documents.theblackvault.com/documents/jfk/jfk-assassination-files.pdf" "$DIR/jfk-assassination-files.pdf" "JFK Assassination Files" + +# --- Pentagon Papers --- +DIR="$BASE/government/pentagon-papers" +mkdir -p "$DIR" +echo "--- Pentagon Papers ---" | tee -a $LOG +download "https://www.archives.gov/files/research/pentagon-papers/pentagon-papers-overview.pdf" "$DIR/pentagon-papers-overview.pdf" "Pentagon Papers Overview" +download "https://documents.theblackvault.com/documents/pentagon-papers/pentagon-papers.pdf" "$DIR/pentagon-papers.pdf" "Pentagon Papers" + +# --- Watergate --- +DIR="$BASE/government/watergate" +mkdir -p "$DIR" +echo "--- Watergate ---" | tee -a $LOG +download "https://vault.fbi.gov/watergate/watergate-part-01-of/view" "$DIR/watergate-fbi-part1.pdf" "Watergate FBI Part 1" +download "https://documents.theblackvault.com/documents/fbifiles/watergate.pdf" "$DIR/watergate-fbi.pdf" "Watergate FBI Files" + +# --- Iran-Contra --- +DIR="$BASE/government/iran-contra" +mkdir -p "$DIR" +echo "--- Iran-Contra ---" | tee -a $LOG +download "https://nsarchive2.gwu.edu/NSAEBB/NSAEBB210/iran-contra-guide.pdf" "$DIR/iran-contra-guide.pdf" "Iran-Contra Guide" +download "https://documents.theblackvault.com/documents/cia/iran-contra.pdf" "$DIR/iran-contra-cia.pdf" "Iran-Contra CIA" + +# --- CIA Torture Report --- +DIR="$BASE/government/cia-torture-report" +mkdir -p "$DIR" +echo "--- CIA Torture Report (SSCI) ---" | tee -a $LOG +download "https://www.intelligence.senate.gov/sites/default/files/publications/CRPT-113srpt288.pdf" "$DIR/ssci-cia-torture-report-executive-summary.pdf" "SSCI Torture Report Executive Summary" +download "https://documents.theblackvault.com/documents/cia/cia-torture-report.pdf" "$DIR/cia-torture-report.pdf" "CIA Torture Report" + + +############################################# +# SUMMARY +############################################# +echo "" | tee -a $LOG +echo "========== DOWNLOAD SUMMARY ==========" | tee -a $LOG +echo "" | tee -a $LOG + +# Count files per directory +for dir in $(find $BASE -type d | sort); do + count=$(find "$dir" -maxdepth 1 -type f -name '*.pdf' | wc -l) + if [ "$count" -gt 0 ]; then + size=$(du -sh "$dir" 2>/dev/null | cut -f1) + echo " $dir: $count files ($size)" | tee -a $LOG + fi +done + +echo "" | tee -a $LOG +TOTAL_FILES=$(find $BASE -type f -name '*.pdf' | wc -l) +TOTAL_SIZE=$(du -sh $BASE 2>/dev/null | cut -f1) +echo "TOTAL: $TOTAL_FILES PDF files, $TOTAL_SIZE" | tee -a $LOG +echo "=== Download complete - $(date) ===" | tee -a $LOG diff --git a/download_v2.sh b/download_v2.sh new file mode 100644 index 0000000..ff92152 --- /dev/null +++ b/download_v2.sh @@ -0,0 +1,337 @@ +#!/bin/bash +# Improved download script using curl with proper User-Agent headers +# Many .gov and archive sites block bare wget + +BASE="/var/www/jaeswift-homepage/unredacted/docs" +LOG="/tmp/download_v2_log.txt" +UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + +echo "=== Download V2 - $(date) ===" | tee $LOG + +dl() { + local url="$1" + local dest="$2" + local name="$3" + # Skip if file already exists and is >1KB + if [ -f "$dest" ] && [ $(stat -c%s "$dest" 2>/dev/null || echo 0) -gt 1000 ]; then + local sz=$(echo "scale=2; $(stat -c%s "$dest")/1048576" | bc) + echo " [SKIP] $name - already exists (${sz}MB)" | tee -a $LOG + return 0 + fi + echo "[DL] $name" | tee -a $LOG + if curl -sS -L -f --connect-timeout 30 --max-time 300 \ + -H "User-Agent: $UA" \ + -H "Accept: application/pdf,*/*" \ + -o "$dest" "$url" 2>/dev/null; then + local size=$(stat -c%s "$dest" 2>/dev/null || echo 0) + if [ "$size" -gt 1000 ]; then + local sizemb=$(echo "scale=2; $size/1048576" | bc) + echo " [OK] ${sizemb}MB" | tee -a $LOG + return 0 + else + echo " [FAIL] Too small (${size}B)" | tee -a $LOG + rm -f "$dest" + return 1 + fi + else + echo " [FAIL] curl error" | tee -a $LOG + rm -f "$dest" + return 1 + fi +} + +############################################### +# SECTION 1: UFO/UAP - USA +############################################### +echo "" | tee -a $LOG +echo "===== PENTAGON UAP REPORTS =====" | tee -a $LOG +DIR="$BASE/ufo-uap/USA/pentagon-uap-reports" +mkdir -p "$DIR" + +# ODNI Preliminary Assessment 2021 +dl "https://www.dni.gov/files/ODNI/documents/assessments/Prelimary-Assessment-UAP-20210625.pdf" \ + "$DIR/dni-preliminary-assessment-uap-2021.pdf" "ODNI Preliminary Assessment 2021" + +# Alternate URL for ODNI 2021 +dl "https://www.dni.gov/files/documents/FOIA/DF-2021-00275-Preliminary-Assessment-Unidentified-Aerial-Phenomena.pdf" \ + "$DIR/dni-preliminary-assessment-uap-2021-foia.pdf" "ODNI 2021 FOIA Version" + +# ODNI Annual Report 2022 +dl "https://www.dni.gov/files/ODNI/documents/assessments/Unclassified-2022-Annual-Report-UAP.pdf" \ + "$DIR/dni-annual-report-uap-2022.pdf" "ODNI Annual Report 2022" + +# AARO Historical Record Vol 1 (March 2024) +dl "https://media.defense.gov/2024/Mar/08/2003409233/-1/-1/0/DOPSR-CLEARED-508-COMPLIANT-HRRV1-08-MAR-2024-FINAL.PDF" \ + "$DIR/aaro-historical-record-vol1-2024.pdf" "AARO Historical Record Vol 1" + +# FY2024 Consolidated Annual Report +dl "https://media.defense.gov/2024/Nov/14/2003583603/-1/-1/0/FY24-CONSOLIDATED-ANNUAL-REPORT-ON-UAP-508.PDF" \ + "$DIR/fy2024-consolidated-annual-report-uap.pdf" "FY2024 UAP Report" + +# DoD IG Evaluation +dl "https://media.defense.gov/2024/Jan/25/2003381266/-1/-1/1/UNCLASSIFIED%20SUMMARY_UNIDENTIFIED%20ANOMALOUS%20PHENOMENA%20SECURE.PDF" \ + "$DIR/dodig-2023-109-uap-evaluation.pdf" "DoD IG UAP Evaluation" + +# Deputy SecDef Memo +dl "https://media.defense.gov/2021/Jun/25/2002749916/-1/-1/1/DEPUTY-SECRETARY-OF-DEFENSE-MEMORANDUM-ON-UNIDENTIFIED-AERIAL-PHENOMENA-ASSESSMENTS.PDF" \ + "$DIR/depsecdef-memo-uap-2021.pdf" "DepSecDef UAP Memo 2021" + +# AARO Nov 2024 consolidated +dl "https://www.dni.gov/files/ODNI/documents/assessments/DOD-AARO-Consolidated-Annual-Report-on-UAP-Nov2024.pdf" \ + "$DIR/aaro-consolidated-nov2024.pdf" "AARO Consolidated Nov 2024" + +echo "" | tee -a $LOG +echo "===== PROJECT BLUE BOOK =====" | tee -a $LOG +DIR="$BASE/ufo-uap/USA/project-blue-book" +mkdir -p "$DIR" + +# Blue Book from Black Vault (this one worked before at 0.57MB) +# Try more Blue Book sources +dl "https://documents.theblackvault.com/documents/ufos/bluebook/bluebook-unknowns.pdf" \ + "$DIR/blue-book-unknowns.pdf" "Blue Book Unknowns" +dl "https://documents.theblackvault.com/documents/ufos/bluebook/bb-specialreport14.pdf" \ + "$DIR/blue-book-special-report-14.pdf" "Blue Book Special Report 14" +dl "https://media.defense.gov/2011/Jul/19/2001713839/-1/-1/0/AFD-101027-030.pdf" \ + "$DIR/blue-book-special-report-14-usaf.pdf" "Blue Book SR14 USAF" + +echo "" | tee -a $LOG +echo "===== CIA UFO COLLECTION =====" | tee -a $LOG +DIR="$BASE/ufo-uap/USA/cia-ufo-collection" +mkdir -p "$DIR" + +# CIA Reading Room UFO docs (known stable URLs) +dl "https://www.cia.gov/readingroom/docs/DOC_0000015467.pdf" \ + "$DIR/cia-ufo-doc-0000015467.pdf" "CIA UFO Doc 15467" +dl "https://www.cia.gov/readingroom/docs/DOC_0000015468.pdf" \ + "$DIR/cia-ufo-doc-0000015468.pdf" "CIA UFO Doc 15468" +dl "https://www.cia.gov/readingroom/docs/DOC_0000042353.pdf" \ + "$DIR/cia-ufo-doc-0000042353.pdf" "CIA UFO Doc 42353" +dl "https://www.cia.gov/readingroom/docs/DOC_0005516020.pdf" \ + "$DIR/cia-ufo-doc-0005516020.pdf" "CIA UFO Doc 5516020" +dl "https://www.cia.gov/readingroom/docs/DOC_0005517742.pdf" \ + "$DIR/cia-ufo-doc-0005517742.pdf" "CIA UFO Doc 5517742" +dl "https://www.cia.gov/readingroom/docs/DOC_0005517761.pdf" \ + "$DIR/cia-ufo-doc-0005517761.pdf" "CIA UFO Doc 5517761" + +echo "" | tee -a $LOG +echo "===== NSA UFO DOCUMENTS =====" | tee -a $LOG +DIR="$BASE/ufo-uap/USA/nsa-ufo-documents" +mkdir -p "$DIR" + +# NSA FOIA UFO docs (nsa.gov) +dl "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/ufo_hypothesis.pdf" \ + "$DIR/nsa-ufo-hypothesis.pdf" "NSA UFO Hypothesis" +dl "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/in_camera_affidavit.pdf" \ + "$DIR/nsa-in-camera-affidavit.pdf" "NSA In Camera Affidavit" +dl "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/key_to_extraterrestrial_messages.pdf" \ + "$DIR/nsa-key-to-et-messages.pdf" "NSA Key to ET Messages" +dl "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/yeoman_1st_class.pdf" \ + "$DIR/nsa-yeoman-report.pdf" "NSA Yeoman Report" +dl "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/now_you_see.pdf" \ + "$DIR/nsa-now-you-see.pdf" "NSA Now You See" +dl "https://www.nsa.gov/portals/75/documents/news-features/declassified-documents/ufo/report_unidentified_flying_objects.pdf" \ + "$DIR/nsa-report-ufos.pdf" "NSA Report UFOs" + +############################################### +# SECTION 1b: UFO/UAP - International +############################################### +echo "" | tee -a $LOG +echo "===== FRANCE: COMETA REPORT =====" | tee -a $LOG +DIR="$BASE/ufo-uap/FR/cometa-report" +mkdir -p "$DIR" + +dl "https://web.archive.org/web/2023/https://www.ufoevidence.org/newsite/files/COMETA-part1.pdf" \ + "$DIR/cometa-report-part1.pdf" "COMETA Part 1 (Archive)" +dl "https://web.archive.org/web/2023/https://www.ufoevidence.org/newsite/files/COMETA-part2.pdf" \ + "$DIR/cometa-report-part2.pdf" "COMETA Part 2 (Archive)" + +echo "" | tee -a $LOG +echo "===== BRAZIL: OPERATION SAUCER =====" | tee -a $LOG +DIR="$BASE/ufo-uap/BR/operation-saucer" +mkdir -p "$DIR" + +# Try Wayback Machine for Black Vault Brazil docs +dl "https://web.archive.org/web/2024/https://documents.theblackvault.com/documents/ufos/brazil/brazil-ufo-night-official-document.pdf" \ + "$DIR/brazil-ufo-official.pdf" "Brazil UFO Official" + +echo "" | tee -a $LOG +echo "===== AUSTRALIA: RAAF FILES =====" | tee -a $LOG +DIR="$BASE/ufo-uap/AU/raaf-ufo-files" +mkdir -p "$DIR" + +# NAA Australia UFO files +dl "https://recordsearch.naa.gov.au/SearchNRetrieve/NAAMedia/ShowImage.aspx?B=30030606&S=1" \ + "$DIR/naa-30030606.pdf" "NAA Record 30030606" + +echo "" | tee -a $LOG +echo "===== CANADA: PROJECT MAGNET =====" | tee -a $LOG +DIR="$BASE/ufo-uap/CA/project-magnet" +mkdir -p "$DIR" + +# Project Magnet - Try Wayback +dl "https://web.archive.org/web/2024/https://documents.theblackvault.com/documents/ufos/canada/project-magnet.pdf" \ + "$DIR/project-magnet.pdf" "Project Magnet" + +echo "" | tee -a $LOG +echo "===== NEW ZEALAND: NZDF FILES =====" | tee -a $LOG +DIR="$BASE/ufo-uap/NZ/nzdf-ufo-files" +mkdir -p "$DIR" + +# NZDF released files +dl "https://www.nzdf.mil.nz/assets/Downloads/NZDF-UFO-Files.pdf" \ + "$DIR/nzdf-ufo-files.pdf" "NZDF UFO Files" + +############################################### +# SECTION 2: COVERT OPERATIONS +############################################### +echo "" | tee -a $LOG +echo "===== MKULTRA =====" | tee -a $LOG +DIR="$BASE/covert-operations/mkultra" +mkdir -p "$DIR" + +dl "https://www.cia.gov/readingroom/docs/DOC_0000017468.pdf" \ + "$DIR/mkultra-doc-0000017468.pdf" "MKUltra Doc 17468" +dl "https://www.cia.gov/readingroom/docs/CIA-RDP88-01315R000300110021-8.pdf" \ + "$DIR/mkultra-cia-rdp88.pdf" "MKUltra CIA RDP88" +dl "https://www.intelligence.senate.gov/sites/default/files/hearings/95mkultra.pdf" \ + "$DIR/mkultra-senate-hearing-1977.pdf" "MKUltra Senate Hearing 1977" + +echo "" | tee -a $LOG +echo "===== COINTELPRO =====" | tee -a $LOG +DIR="$BASE/covert-operations/cointelpro" +mkdir -p "$DIR" + +dl "https://vault.fbi.gov/cointel-pro/cointel-pro-black-extremist/cointelpro-black-extremists-part-01-of/at_download/file" \ + "$DIR/cointelpro-black-extremists-part1.pdf" "COINTELPRO Black Extremists Pt1" +dl "https://vault.fbi.gov/cointel-pro/cointel-pro-white-hate/cointelpro-white-hate-groups-part-01-of/at_download/file" \ + "$DIR/cointelpro-white-hate-part1.pdf" "COINTELPRO White Hate Pt1" +dl "https://vault.fbi.gov/cointel-pro/new-left/cointelpro-new-left-part-01-of/at_download/file" \ + "$DIR/cointelpro-new-left-part1.pdf" "COINTELPRO New Left Pt1" + +echo "" | tee -a $LOG +echo "===== STARGATE PROGRAM =====" | tee -a $LOG +DIR="$BASE/covert-operations/stargate-program" +mkdir -p "$DIR" + +dl "https://www.cia.gov/readingroom/docs/CIA-RDP96-00788R001700210016-5.pdf" \ + "$DIR/stargate-remote-viewing-session-1.pdf" "Stargate RV Session 1" +dl "https://www.cia.gov/readingroom/docs/CIA-RDP96-00789R003100030001-4.pdf" \ + "$DIR/stargate-remote-viewing-session-2.pdf" "Stargate RV Session 2" +dl "https://www.cia.gov/readingroom/docs/CIA-RDP96-00787R000500250001-0.pdf" \ + "$DIR/stargate-project-sun-streak.pdf" "Stargate Sun Streak" +dl "https://www.cia.gov/readingroom/docs/CIA-RDP96-00788R001900680001-4.pdf" \ + "$DIR/stargate-evaluation.pdf" "Stargate Evaluation" + +echo "" | tee -a $LOG +echo "===== OPERATION NORTHWOODS =====" | tee -a $LOG +DIR="$BASE/covert-operations/operation-northwoods" +mkdir -p "$DIR" + +dl "https://nsarchive2.gwu.edu/news/20010430/northwoods.pdf" \ + "$DIR/operation-northwoods.pdf" "Operation Northwoods" +# Backup from archive.org +dl "https://web.archive.org/web/2024/https://nsarchive2.gwu.edu/news/20010430/northwoods.pdf" \ + "$DIR/operation-northwoods.pdf" "Operation Northwoods (Archive)" + +echo "" | tee -a $LOG +echo "===== OPERATION MOCKINGBIRD =====" | tee -a $LOG +DIR="$BASE/covert-operations/operation-mockingbird" +mkdir -p "$DIR" + +# Church Committee Report on CIA media manipulation +dl "https://www.intelligence.senate.gov/sites/default/files/94755_I.pdf" \ + "$DIR/church-committee-book1.pdf" "Church Committee Book I" +dl "https://www.intelligence.senate.gov/sites/default/files/94755_II.pdf" \ + "$DIR/church-committee-book2.pdf" "Church Committee Book II" +dl "https://www.intelligence.senate.gov/sites/default/files/94755_III.pdf" \ + "$DIR/church-committee-book3.pdf" "Church Committee Book III" + +echo "" | tee -a $LOG +echo "===== OPERATION PAPERCLIP =====" | tee -a $LOG +DIR="$BASE/covert-operations/operation-paperclip" +mkdir -p "$DIR" + +dl "https://nsarchive2.gwu.edu/NSAEBB/NSAEBB146/doc1.pdf" \ + "$DIR/paperclip-jioa-memo.pdf" "Paperclip JIOA Memo" +dl "https://web.archive.org/web/2024/https://nsarchive2.gwu.edu/NSAEBB/NSAEBB146/doc1.pdf" \ + "$DIR/paperclip-jioa-memo.pdf" "Paperclip JIOA (Archive)" + +############################################### +# SECTION 3: GOVERNMENT +############################################### +echo "" | tee -a $LOG +echo "===== JFK ASSASSINATION =====" | tee -a $LOG +DIR="$BASE/government/jfk-assassination" +mkdir -p "$DIR" + +# Warren Commission +dl "https://www.archives.gov/research/jfk/warren-commission-report/warren-commission-report.pdf" \ + "$DIR/warren-commission-report.pdf" "Warren Commission Report" +# Try history-matters for Warren Commission +dl "https://history-matters.com/archive/jfk/wc/wr/pdf/WC_Vol0.pdf" \ + "$DIR/warren-commission-vol0.pdf" "Warren Commission Vol 0" +dl "https://www.maryferrell.org/showDoc.html?docId=946" \ + "$DIR/jfk-mary-ferrell.pdf" "JFK Mary Ferrell" + +echo "" | tee -a $LOG +echo "===== PENTAGON PAPERS =====" | tee -a $LOG +DIR="$BASE/government/pentagon-papers" +mkdir -p "$DIR" + +dl "https://www.archives.gov/research/pentagon-papers" \ + "$DIR/pentagon-papers-nara.pdf" "Pentagon Papers NARA" +dl "https://media.nara.gov/research/pentagon-papers/Pentagon-Papers-Part-I.pdf" \ + "$DIR/pentagon-papers-part1.pdf" "Pentagon Papers Part I" + +echo "" | tee -a $LOG +echo "===== WATERGATE =====" | tee -a $LOG +DIR="$BASE/government/watergate" +mkdir -p "$DIR" + +dl "https://vault.fbi.gov/watergate/watergate-part-01-of/at_download/file" \ + "$DIR/watergate-fbi-part1.pdf" "Watergate FBI Part 1" + +echo "" | tee -a $LOG +echo "===== IRAN-CONTRA =====" | tee -a $LOG +DIR="$BASE/government/iran-contra" +mkdir -p "$DIR" + +dl "https://nsarchive2.gwu.edu/NSAEBB/NSAEBB210/iran-contra-guide.pdf" \ + "$DIR/iran-contra-guide.pdf" "Iran-Contra Guide" +dl "https://web.archive.org/web/2024/https://nsarchive2.gwu.edu/NSAEBB/NSAEBB210/iran-contra-guide.pdf" \ + "$DIR/iran-contra-guide.pdf" "Iran-Contra Guide (Archive)" + +echo "" | tee -a $LOG +echo "===== CIA TORTURE REPORT =====" | tee -a $LOG +DIR="$BASE/government/cia-torture-report" +mkdir -p "$DIR" + +# SSCI Torture Report Executive Summary (525 pages) +dl "https://www.intelligence.senate.gov/sites/default/files/publications/CRPT-113srpt288.pdf" \ + "$DIR/ssci-torture-report-executive-summary.pdf" "SSCI Torture Report" +# Feinstein CIA study +dl "https://www.feinstein.senate.gov/public/_cache/files/7/c/7c85429a-ec38-4bb5-968f-289799bf6d0e/D87288C34A6D9FF736F9459ABCF83210.sscistudy1.pdf" \ + "$DIR/feinstein-cia-study.pdf" "Feinstein CIA Study" + + +############################################### +# SUMMARY +############################################### +echo "" | tee -a $LOG +echo "========== DOWNLOAD V2 SUMMARY ==========" | tee -a $LOG +echo "" | tee -a $LOG + +for dir in $(find $BASE -type d | sort); do + count=$(find "$dir" -maxdepth 1 -type f \( -name '*.pdf' -o -name '*.PDF' \) | wc -l) + if [ "$count" -gt 0 ]; then + size=$(du -sh "$dir" 2>/dev/null | cut -f1) + echo " $dir: $count files ($size)" | tee -a $LOG + fi +done + +echo "" | tee -a $LOG +# Include UK existing docs in total +TOTAL_FILES=$(find $BASE -type f \( -name '*.pdf' -o -name '*.PDF' \) | wc -l) +TOTAL_SIZE=$(du -sh $BASE 2>/dev/null | cut -f1) +echo "TOTAL: $TOTAL_FILES PDF files, $TOTAL_SIZE total" | tee -a $LOG +echo "=== Download V2 complete - $(date) ===" | tee -a $LOG diff --git a/js/crimescene.js b/js/crimescene.js new file mode 100644 index 0000000..3e4c9d2 --- /dev/null +++ b/js/crimescene.js @@ -0,0 +1,1023 @@ +/* ═══════════════════════════════════════════════════════ + CRIME SCENE — Criminal Case Archive + SPA Engine with hash routing & PDF.js viewer + ═══════════════════════════════════════════════════════ */ + +(function () { + 'use strict'; + + const ROOT = document.getElementById('crimesceneRoot'); + const PDF_BASE = '/crimescene/docs'; + let DATA = null; + + // ─── Data Loading ──────────────────────────────────── + async function loadData() { + try { + const r = await fetch('/api/crimescene'); + if (!r.ok) throw new Error(`HTTP ${r.status}`); + DATA = await r.json(); + } catch (e) { + console.error('CRIMESCENE: data load failed', e); + ROOT.innerHTML = `
+
⚠️
+
CASE DATABASE OFFLINE
+
Failed to load criminal case index. ${e.message}
+
`; + } + } + + // ─── Helpers ────────────────────────────────────────── + function countDocuments(obj) { + if (!obj) return 0; + if (Array.isArray(obj.documents)) return obj.documents.length; + if (Array.isArray(obj.collections)) { + return obj.collections.reduce((s, c) => s + (c.documents ? c.documents.length : 0), 0); + } + if (Array.isArray(obj.countries)) { + return obj.countries.reduce((s, cn) => s + countDocuments(cn), 0); + } + return 0; + } + + function countCollections(obj) { + if (!obj) return 0; + if (Array.isArray(obj.collections)) return obj.collections.length; + if (Array.isArray(obj.countries)) { + return obj.countries.reduce((s, cn) => s + (cn.collections ? cn.collections.length : 0), 0); + } + return 0; + } + + function countCountries(cat) { + return cat.countries ? cat.countries.length : 0; + } + + function totalStats() { + if (!DATA || !DATA.categories) return { cats: 0, countries: 0, collections: 0, docs: 0 }; + let countries = new Set(); + let collections = 0; + let docs = 0; + DATA.categories.forEach(cat => { + (cat.countries || []).forEach(cn => { + countries.add(cn.code); + (cn.collections || []).forEach(col => { + collections++; + docs += (col.documents || []).length; + }); + }); + }); + return { cats: DATA.categories.length, countries: countries.size, collections, docs }; + } + + function findCategory(id) { + return DATA.categories.find(c => c.id === id); + } + + function findCountry(cat, code) { + return (cat.countries || []).find(c => c.code === code); + } + + function findCollection(country, colId) { + return (country.collections || []).find(c => c.id === colId); + } + + function findDocument(collection, docId) { + return (collection.documents || []).find(d => d.id === docId); + } + + function esc(s) { + const d = document.createElement('div'); + d.textContent = s || ''; + return d.innerHTML; + } + + // ─── Breadcrumb Builder ─────────────────────────────── + function breadcrumb(parts) { + // parts: [{label, hash?}, ...] + let html = '
'; + return html; + } + + // ─── View: Categories (Home) ────────────────────────── + function renderCategories() { + const stats = totalStats(); + let html = ''; + + html += `
CRIMINAL CASE ARCHIVE // ACCESS GRANTED
`; + + html += `
+
CATEGORIES${stats.cats}
+
COUNTRIES${stats.countries}
+
COLLECTIONS${stats.collections}
+
DOCUMENTS${stats.docs}
+
`; + + html += breadcrumb([{ label: 'CRIME SCENE' }]); + + // ─── Global Search Bar ──────────────────────────────── + html += `
+ +
+
+
`; + + html += '
'; + html += ''; + + DATA.categories.forEach(cat => { + const nCountries = countCountries(cat); + const nDocs = countDocuments(cat); + const nCol = countCollections(cat); + html += `
+
+
${esc(cat.name)}
+
${cat.icon || '📁'}
+
+
${esc(cat.description)}
+
+ ${nCountries} COUNTR${nCountries === 1 ? 'Y' : 'IES'} · ${nCol} COLLECTION${nCol === 1 ? '' : 'S'} + ${nDocs} DOC${nDocs === 1 ? '' : 'S'} +
+
`; + }); + + html += '
'; + html += ''; // close #csCategorySection + ROOT.innerHTML = html; + + // ─── Bind search events ──────────────────────────────── + initSearchListeners(); + } + + // ─── View: Category (Country Selector + Collections) ── + function renderCategory(catId, activeCountry) { + const cat = findCategory(catId); + if (!cat) return renderNotFound('Category not found'); + + let html = ''; + html += `
CASE FILE // ${esc(cat.name)} // ACCESS GRANTED
`; + + html += breadcrumb([ + { label: 'CRIME SCENE', hash: '' }, + { label: cat.name } + ]); + + // Country selector + if (cat.countries && cat.countries.length > 0) { + html += ''; + html += '
'; + cat.countries.forEach(cn => { + const nCol = cn.collections ? cn.collections.length : 0; + const isActive = activeCountry === cn.code; + html += `
+ ${cn.flag || ''} + ${esc(cn.name)} + [${nCol}] +
`; + }); + html += '
'; + + // If a country is selected, show its collections + if (activeCountry) { + const country = findCountry(cat, activeCountry); + if (country) { + html += renderCountryCollections(cat, country); + } + } else { + // Show all collections from all countries + html += ''; + let hasCols = false; + cat.countries.forEach(cn => { + if (cn.collections && cn.collections.length > 0) { + hasCols = true; + } + }); + if (hasCols) { + html += '
'; + cat.countries.forEach(cn => { + (cn.collections || []).forEach(col => { + html += renderCollectionCard(catId, cn.code, col, cn.flag); + }); + }); + html += '
'; + } else { + html += renderEmpty('NO COLLECTIONS YET', 'Collections will appear here once documents are added to this category.'); + } + } + } else { + html += renderEmpty('NO COUNTRIES REGISTERED', 'No country data available for this category yet.'); + } + + ROOT.innerHTML = html; + } + + function renderCountryCollections(cat, country) { + let html = ''; + html += ``; + + if (country.collections && country.collections.length > 0) { + html += '
'; + country.collections.forEach(col => { + html += renderCollectionCard(cat.id, country.code, col); + }); + html += '
'; + } else { + html += renderEmpty('NO COLLECTIONS', 'No document collections available for this country yet.'); + } + return html; + } + + function renderCollectionCard(catId, countryCode, col, flag) { + const nDocs = col.documents ? col.documents.length : 0; + return `
+
${flag ? flag + ' ' : ''}${esc(col.name)}
+
${esc(col.year)}
+
${esc(col.description)}
+ +
`; + } + + // ─── View: Collection (Documents) ───────────────────── + function renderCollection(catId, countryCode, colId) { + const cat = findCategory(catId); + if (!cat) return renderNotFound('Category not found'); + const country = findCountry(cat, countryCode); + if (!country) return renderNotFound('Country not found'); + const col = findCollection(country, colId); + if (!col) return renderNotFound('Collection not found'); + + let html = ''; + html += `
CASE FILE // ${esc(col.name).toUpperCase()} // ACCESS GRANTED
`; + + html += breadcrumb([ + { label: 'CRIME SCENE', hash: '' }, + { label: cat.name, hash: `category/${catId}` }, + { label: `${country.flag || ''} ${country.name}`, hash: `country/${catId}/${countryCode}` }, + { label: col.name } + ]); + + // Detail header + html += `
+
${esc(col.name)}
+
${esc(col.year)}
+
${esc(col.description)}
+
SOURCE: ${esc(col.source)}
+
`; + + // Documents + if (col.documents && col.documents.length > 0) { + html += ``; + html += '
'; + col.documents.forEach(doc => { + html += `
+
📄
+
+
${esc(doc.title)}
+
${esc(doc.description)}
+
+ PAGES: ${doc.pages || '?'} + RELEASED: ${esc(doc.date_released || 'UNKNOWN')} + ${esc(doc.filename)} +
+
+
VIEW
+
`; + }); + html += '
'; + } else { + html += renderEmpty('NO DOCUMENTS UPLOADED YET', 'This collection has been catalogued but documents have not yet been uploaded to the archive.'); + } + + ROOT.innerHTML = html; + } + + // ─── View: Document (PDF Viewer) ────────────────────── + function renderDocument(catId, countryCode, colId, docId) { + const cat = findCategory(catId); + if (!cat) return renderNotFound('Category not found'); + const country = findCountry(cat, countryCode); + if (!country) return renderNotFound('Country not found'); + const col = findCollection(country, colId); + if (!col) return renderNotFound('Collection not found'); + const doc = findDocument(col, docId); + if (!doc) return renderNotFound('Document not found'); + + const pdfUrl = `${PDF_BASE}/${catId}/${colId}/${doc.filename}`; + + let html = ''; + html += `
CASE FILE // ${esc(doc.title).toUpperCase()}
`; + + html += breadcrumb([ + { label: 'CRIME SCENE', hash: '' }, + { label: cat.name, hash: `category/${catId}` }, + { label: `${country.flag || ''} ${country.name}`, hash: `country/${catId}/${countryCode}` }, + { label: col.name, hash: `collection/${catId}/${countryCode}/${colId}` }, + { label: doc.title } + ]); + + // Viewer + html += `
+
+
${esc(doc.title)}
+
+ + — / — + + + + + + ⬇ DOWNLOAD +
+
+ +
+
RETRIEVING CASE FILE...
+
+
`; + + // Doc info + html += `
+
${esc(doc.title)}
+
${esc(doc.description)}
+
+ PAGES: ${doc.pages || '?'} + RELEASED: ${esc(doc.date_released || 'UNKNOWN')} + FILE: ${esc(doc.filename)} +
+
`; + + ROOT.innerHTML = html; + + // Init PDF viewer + initPdfViewer(pdfUrl); + } + + // ─── PDF.js Viewer ─────────────────────────────────── + let pdfDoc = null; + let pdfPage = 1; + let pdfScale = 1.5; + let pdfRendering = false; + let pdfPending = null; + let pdfAllText = []; + let pdfSearchActive = false; + let pdfSearchQuery = ''; + let pdfSearchCaseSensitive = false; + let pdfSearchMatches = []; + let pdfSearchCurrentIdx = -1; + + + async function initPdfViewer(url) { + const canvasWrap = document.getElementById('pdfCanvasWrap'); + const loadingEl = document.getElementById('pdfLoading'); + const pageInfo = document.getElementById('pdfPageInfo'); + + // Check if pdf.js is loaded + if (typeof pdfjsLib === 'undefined') { + canvasWrap.innerHTML = `
+
⚠️
+
PDF.js library not loaded
+ ⬇ DOWNLOAD PDF DIRECTLY +
`; + return; + } + + try { + pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'; + const loadingTask = pdfjsLib.getDocument(url); + pdfDoc = await loadingTask.promise; + pdfPage = 1; + + loadingEl.remove(); + + // Create page container with canvas + const pageContainer = document.createElement('div'); + pageContainer.id = 'pdfPageContainer'; + pageContainer.className = 'prop-page-container'; + const canvas = document.createElement('canvas'); + canvas.id = 'pdfCanvas'; + pageContainer.appendChild(canvas); + canvasWrap.appendChild(pageContainer); + + updatePageInfo(); + renderPdfPage(); + + // Controls + document.getElementById('pdfPrev').addEventListener('click', () => { + if (pdfPage <= 1) return; + pdfPage--; + queueRender(); + }); + document.getElementById('pdfNext').addEventListener('click', () => { + if (pdfPage >= pdfDoc.numPages) return; + pdfPage++; + queueRender(); + }); + document.getElementById('pdfZoomIn').addEventListener('click', () => { + pdfScale = Math.min(pdfScale + 0.25, 4); + queueRender(); + }); + document.getElementById('pdfZoomOut').addEventListener('click', () => { + pdfScale = Math.max(pdfScale - 0.25, 0.5); + queueRender(); + }); + document.getElementById('pdfFit').addEventListener('click', () => { + pdfScale = 1.5; + queueRender(); + }); + + // Extract all page text for search + extractAllText(); + + // Initialize search controls + initSearchControls(); + } catch (e) { + console.error('PDF load failed:', e); + canvasWrap.innerHTML = `
+
⚠️
+
DOCUMENT LOAD FAILED — ${esc(e.message || 'File may not exist yet')}
+ ⬇ ATTEMPT DIRECT DOWNLOAD +
`; + } + } + + function updatePageInfo() { + const el = document.getElementById('pdfPageInfo'); + if (el && pdfDoc) { + el.textContent = `${pdfPage} / ${pdfDoc.numPages}`; + } + } + + async function renderPdfPage() { + if (!pdfDoc) return; + pdfRendering = true; + + const page = await pdfDoc.getPage(pdfPage); + const viewport = page.getViewport({ scale: pdfScale }); + const canvas = document.getElementById('pdfCanvas'); + if (!canvas) { pdfRendering = false; return; } + const ctx = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + + // Update page container size to match viewport + const pageContainer = document.getElementById('pdfPageContainer'); + if (pageContainer) { + pageContainer.style.width = viewport.width + 'px'; + pageContainer.style.height = viewport.height + 'px'; + } + + await page.render({ canvasContext: ctx, viewport: viewport }).promise; + + // Render text layer for search and text selection + await renderPageTextLayer(page, viewport); + + // Highlight search matches on this page + highlightCurrentPageMatches(); + + pdfRendering = false; + updatePageInfo(); + + if (pdfPending !== null) { + renderPdfPage(); + pdfPending = null; + } + } + + function queueRender() { + if (pdfRendering) { + pdfPending = pdfPage; + } else { + renderPdfPage(); + } + } + + // ─── Text Layer Rendering ──────────────────────────── + async function renderPageTextLayer(page, viewport) { + const existing = document.getElementById('pdfTextLayer'); + if (existing) existing.remove(); + + const pageContainer = document.getElementById('pdfPageContainer'); + if (!pageContainer) return; + + const textContent = await page.getTextContent(); + const textLayerDiv = document.createElement('div'); + textLayerDiv.id = 'pdfTextLayer'; + textLayerDiv.className = 'prop-text-layer'; + textLayerDiv.style.width = viewport.width + 'px'; + textLayerDiv.style.height = viewport.height + 'px'; + + // Try pdf.js built-in renderTextLayer, fallback to manual + if (typeof pdfjsLib.renderTextLayer === 'function') { + try { + const task = pdfjsLib.renderTextLayer({ + textContentSource: textContent, + container: textLayerDiv, + viewport: viewport, + }); + await task.promise; + } catch (err) { + console.warn('renderTextLayer failed, using fallback:', err); + buildTextLayerFallback(textContent, viewport, textLayerDiv); + } + } else { + buildTextLayerFallback(textContent, viewport, textLayerDiv); + } + + // Tag each span with its item index for search highlighting + let itemIdx = 0; + for (const child of textLayerDiv.childNodes) { + if (child.nodeName === 'SPAN') { + child.dataset.itemIdx = itemIdx; + itemIdx++; + } + } + + pageContainer.appendChild(textLayerDiv); + } + + function buildTextLayerFallback(textContent, viewport, container) { + textContent.items.forEach((item, idx) => { + if (!item.str) return; + const span = document.createElement('span'); + span.textContent = item.str; + const tx = item.transform; + const fontHeight = Math.sqrt(tx[2] * tx[2] + tx[3] * tx[3]); + const s = viewport.scale; + span.style.fontSize = (fontHeight * s) + 'px'; + span.style.fontFamily = 'sans-serif'; + span.style.left = (tx[4] * s) + 'px'; + span.style.top = (viewport.height - tx[5] * s - fontHeight * s) + 'px'; + span.style.position = 'absolute'; + span.style.color = 'transparent'; + span.style.whiteSpace = 'pre'; + container.appendChild(span); + }); + } + + // ─── Text Extraction for Search ────────────────────── + async function extractAllText() { + pdfAllText = []; + if (!pdfDoc) return; + for (let i = 1; i <= pdfDoc.numPages; i++) { + const page = await pdfDoc.getPage(i); + const tc = await page.getTextContent(); + let fullText = ''; + const itemOffsets = []; + tc.items.forEach((item, idx) => { + const start = fullText.length; + fullText += item.str; + itemOffsets.push({ start: start, end: fullText.length, itemIdx: idx }); + if (item.hasEOL) fullText += '\n'; + }); + pdfAllText.push({ pageNum: i, text: fullText, items: tc.items, itemOffsets: itemOffsets }); + } + console.log('CRIMESCENE: Extracted text from ' + pdfAllText.length + ' pages'); + } + + // ─── Search Controls Init ──────────────────────────── + function initSearchControls() { + const searchInput = document.getElementById('pdfSearchInput'); + const searchPrev = document.getElementById('pdfSearchPrev'); + const searchNext = document.getElementById('pdfSearchNext'); + const searchClose = document.getElementById('pdfSearchClose'); + const searchToggle = document.getElementById('pdfSearchToggle'); + const searchCaseBtn = document.getElementById('pdfSearchCaseBtn'); + if (!searchInput) return; + + searchToggle.addEventListener('click', () => toggleSearchBar()); + searchClose.addEventListener('click', () => closeSearchBar()); + + let searchTimeout = null; + searchInput.addEventListener('input', () => { + clearTimeout(searchTimeout); + searchTimeout = setTimeout(() => { + pdfSearchQuery = searchInput.value; + performSearch(); + }, 200); + }); + + searchInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + if (e.shiftKey) prevMatch(); else nextMatch(); + } + if (e.key === 'Escape') { + e.preventDefault(); + closeSearchBar(); + } + }); + + searchPrev.addEventListener('click', () => prevMatch()); + searchNext.addEventListener('click', () => nextMatch()); + + searchCaseBtn.addEventListener('click', () => { + pdfSearchCaseSensitive = !pdfSearchCaseSensitive; + searchCaseBtn.classList.toggle('active', pdfSearchCaseSensitive); + performSearch(); + }); + + // Ctrl+F shortcut — only when PDF viewer is present + document.addEventListener('keydown', (e) => { + if ((e.ctrlKey || e.metaKey) && e.key === 'f') { + if (document.getElementById('pdfViewerContainer')) { + e.preventDefault(); + toggleSearchBar(true); + } + } + }); + } + + function toggleSearchBar(forceOpen) { + const searchBar = document.getElementById('pdfSearchBar'); + const searchInput = document.getElementById('pdfSearchInput'); + if (!searchBar) return; + if (forceOpen || !pdfSearchActive) { + searchBar.classList.add('active'); + pdfSearchActive = true; + setTimeout(() => searchInput && searchInput.focus(), 50); + } else { + closeSearchBar(); + } + } + + function closeSearchBar() { + const searchBar = document.getElementById('pdfSearchBar'); + if (!searchBar) return; + searchBar.classList.remove('active'); + pdfSearchActive = false; + pdfSearchQuery = ''; + pdfSearchMatches = []; + pdfSearchCurrentIdx = -1; + const searchInput = document.getElementById('pdfSearchInput'); + if (searchInput) searchInput.value = ''; + updateSearchInfo(); + clearHighlights(); + } + + function performSearch() { + pdfSearchMatches = []; + pdfSearchCurrentIdx = -1; + const query = pdfSearchQuery.trim(); + if (!query || query.length === 0) { + updateSearchInfo(); + clearHighlights(); + return; + } + const cs = pdfSearchCaseSensitive; + const q = cs ? query : query.toLowerCase(); + pdfAllText.forEach(pageData => { + const text = cs ? pageData.text : pageData.text.toLowerCase(); + let pos = 0; + while ((pos = text.indexOf(q, pos)) !== -1) { + const matchStart = pos; + const matchEnd = pos + q.length; + const affectedItems = pageData.itemOffsets.filter( + io => io.end > matchStart && io.start < matchEnd + ); + pdfSearchMatches.push({ + page: pageData.pageNum, + charStart: matchStart, + charEnd: matchEnd, + itemIndices: affectedItems.map(io => io.itemIdx) + }); + pos += 1; + } + }); + pdfSearchCurrentIdx = pdfSearchMatches.length > 0 ? 0 : -1; + updateSearchInfo(); + if (pdfSearchMatches.length > 0) { + goToMatch(0); + } else { + clearHighlights(); + } + } + + function goToMatch(idx) { + if (idx < 0 || idx >= pdfSearchMatches.length) return; + pdfSearchCurrentIdx = idx; + const match = pdfSearchMatches[idx]; + if (match.page !== pdfPage) { + pdfPage = match.page; + queueRender(); + } else { + highlightCurrentPageMatches(); + } + updateSearchInfo(); + } + + function nextMatch() { + if (pdfSearchMatches.length === 0) return; + goToMatch((pdfSearchCurrentIdx + 1) % pdfSearchMatches.length); + } + + function prevMatch() { + if (pdfSearchMatches.length === 0) return; + goToMatch((pdfSearchCurrentIdx - 1 + pdfSearchMatches.length) % pdfSearchMatches.length); + } + + function highlightCurrentPageMatches() { + clearHighlights(); + const textLayer = document.getElementById('pdfTextLayer'); + if (!textLayer) return; + const pageMatches = pdfSearchMatches.filter(m => m.page === pdfPage); + if (pageMatches.length === 0) return; + + pageMatches.forEach(match => { + const globalIdx = pdfSearchMatches.indexOf(match); + const isActive = globalIdx === pdfSearchCurrentIdx; + match.itemIndices.forEach(itemIdx => { + const span = textLayer.querySelector('span[data-item-idx="' + itemIdx + '"]'); + if (span) { + span.classList.add('prop-search-hl'); + if (isActive) { + span.classList.add('prop-search-hl-active'); + const canvasWrap = document.getElementById('pdfCanvasWrap'); + if (canvasWrap) { + const sr = span.getBoundingClientRect(); + const wr = canvasWrap.getBoundingClientRect(); + const offset = sr.top - wr.top - wr.height / 3; + canvasWrap.scrollBy({ top: offset, behavior: 'smooth' }); + } + } + } + }); + }); + } + + function clearHighlights() { + const tl = document.getElementById('pdfTextLayer'); + if (!tl) return; + tl.querySelectorAll('.prop-search-hl').forEach(el => { + el.classList.remove('prop-search-hl', 'prop-search-hl-active'); + }); + } + + function updateSearchInfo() { + const info = document.getElementById('pdfSearchInfo'); + if (!info) return; + if (pdfSearchMatches.length === 0) { + if (pdfSearchQuery && pdfSearchQuery.trim().length > 0) { + info.textContent = 'NO MATCHES'; + info.className = 'prop-search-info no-match'; + } else { + info.textContent = ''; + info.className = 'prop-search-info'; + } + } else { + info.textContent = (pdfSearchCurrentIdx + 1) + ' OF ' + pdfSearchMatches.length; + info.className = 'prop-search-info'; + } + } + + + // ─── Global Archive Search ───────────────────────────── + let searchDebounceTimer = null; + + function initSearchListeners() { + const input = document.getElementById('csSearchInput'); + const clearBtn = document.getElementById('csSearchClear'); + if (!input) return; + + input.addEventListener('input', () => { + clearTimeout(searchDebounceTimer); + const val = input.value.trim(); + clearBtn.style.display = val.length > 0 ? 'inline-block' : 'none'; + searchDebounceTimer = setTimeout(() => { + globalArchiveSearch(val); + }, 300); + }); + + clearBtn.addEventListener('click', () => { + input.value = ''; + clearBtn.style.display = 'none'; + globalArchiveSearch(''); + input.focus(); + }); + + input.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + input.value = ''; + clearBtn.style.display = 'none'; + globalArchiveSearch(''); + } + }); + } + + function globalArchiveSearch(query) { + const resultsEl = document.getElementById('csSearchResults'); + const statusEl = document.getElementById('csSearchStatus'); + const catSection = document.getElementById('csCategorySection'); + if (!resultsEl || !statusEl) return; + + if (!query || query.length === 0) { + resultsEl.innerHTML = ''; + statusEl.innerHTML = ''; + if (catSection) catSection.style.display = ''; + return; + } + + const q = query.toLowerCase(); + const results = []; + + if (!DATA || !DATA.categories) return; + + DATA.categories.forEach(cat => { + (cat.countries || []).forEach(cn => { + (cn.collections || []).forEach(col => { + (col.documents || []).forEach(doc => { + const fields = [ + doc.title || '', + doc.description || '', + col.name || '', + cat.name || '', + cn.name || '', + doc.year ? String(doc.year) : '', + doc.classification || '' + ]; + const combined = fields.join(' ').toLowerCase(); + if (combined.includes(q)) { + results.push({ + doc, + catName: cat.name, + catId: cat.id, + catIcon: cat.icon || '📁', + countryName: cn.name, + countryCode: cn.code, + countryFlag: cn.flag || '', + colName: col.name, + colId: col.id + }); + } + }); + + // Also match collection-level (even if no docs match) + const colFields = [col.name || '', col.description || '', cat.name || '', cn.name || ''].join(' ').toLowerCase(); + if (colFields.includes(q) && !results.find(r => r.colId === col.id && r.catId === cat.id && r.countryCode === cn.code && !r.doc.id)) { + // Check if we already added docs from this collection + const hasDocResults = results.some(r => r.colId === col.id && r.catId === cat.id && r.countryCode === cn.code); + if (!hasDocResults) { + results.push({ + doc: { title: col.name, description: col.description || 'Collection in ' + cat.name, id: '__col__' }, + catName: cat.name, + catId: cat.id, + catIcon: cat.icon || '📁', + countryName: cn.name, + countryCode: cn.code, + countryFlag: cn.flag || '', + colName: col.name, + colId: col.id, + isCollection: true + }); + } + } + }); + }); + }); + + // Hide categories when searching + if (catSection) catSection.style.display = 'none'; + + if (results.length === 0) { + statusEl.innerHTML = 'NO MATCHING CASE FILES // REFINE SEARCH PARAMETERS'; + resultsEl.innerHTML = ''; + return; + } + + statusEl.innerHTML = `FOUND ${results.length} MATCHING CASE FILE${results.length === 1 ? '' : 'S'}`; + + let html = '
'; + results.forEach(r => { + const title = highlightMatch(esc(r.doc.title || 'Untitled'), q); + const desc = r.doc.description ? highlightMatch(esc(truncateText(r.doc.description, 160)), q) : ''; + const hash = r.isCollection + ? `country/${r.catId}/${r.countryCode}` + : `doc/${r.catId}/${r.countryCode}/${r.colId}/${r.doc.id}`; + + html += `
+
+ ${r.catIcon} + ${title} +
+
+ ${esc(r.catName)} + ${r.countryFlag} ${esc(r.countryName)} + ${esc(r.colName)} +
+ ${desc ? `
${desc}
` : ''} +
`; + }); + html += '
'; + resultsEl.innerHTML = html; + } + + function highlightMatch(text, query) { + if (!query) return text; + const regex = new RegExp('(' + query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')', 'gi'); + return text.replace(regex, '$1'); + } + + function truncateText(text, maxLen) { + if (text.length <= maxLen) return text; + return text.substring(0, maxLen).replace(/\s+\S*$/, '') + '...'; + } + + // ─── Not Found / Empty ──────────────────────────────── + function renderNotFound(msg) { + ROOT.innerHTML = `
+
⚠️
+
${esc(msg)}
+
The requested case file could not be located in the criminal archive.
+
+
+ ◂ RETURN TO CASE INDEX +
`; + } + + function renderEmpty(title, text) { + return `
+
+
${esc(title)}
+
${esc(text)}
+
`; + } + + // ─── Router ─────────────────────────────────────────── + function route() { + if (!DATA) return; + + // Reset PDF state + pdfDoc = null; + pdfPage = 1; + pdfRendering = false; + pdfPending = null; + pdfAllText = []; + pdfSearchActive = false; + pdfSearchQuery = ''; + pdfSearchMatches = []; + pdfSearchCurrentIdx = -1; + + + const hash = (location.hash || '').replace(/^#\/?/, ''); + const parts = hash.split('/').filter(Boolean); + + if (parts.length === 0 || hash === '') { + renderCategories(); + } else if (parts[0] === 'category' && parts[1]) { + renderCategory(parts[1], null); + } else if (parts[0] === 'country' && parts[1] && parts[2]) { + renderCategory(parts[1], parts[2]); + } else if (parts[0] === 'collection' && parts.length >= 4) { + renderCollection(parts[1], parts[2], parts[3]); + } else if (parts[0] === 'doc' && parts.length >= 5) { + renderDocument(parts[1], parts[2], parts[3], parts[4]); + } else { + renderNotFound('INVALID ROUTE'); + } + + // Scroll to top + window.scrollTo({ top: 0, behavior: 'smooth' }); + } + + // ─── Init ───────────────────────────────────────────── + async function init() { + ROOT.innerHTML = '
INITIALISING CRIME SCENE ARCHIVE...
'; + await loadData(); + if (DATA) { + window.addEventListener('hashchange', route); + route(); + } + } + + // Wait for DOM + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})();