All projects

VkArchiveViewer

★ 0 stars↓ 37 downloadsv1.1.0
Download latest version

README.md

VK Archive Reader

🌐 Open the app in your browser → vkviewer.normno.ru

No installation required—the web version works right in your browser, and your archive is processed locally on your device and isn’t sent anywhere. Want a native app? Check out the “Download and Install” section.


A convenient reader for your VKontakte archive. When you download your data from VK, it comes as a collection of “raw” web pages that are inconvenient to browse and in which you can’t search properly. This app transforms them into a familiar messaging app: a list of chats, the ability to read conversations, search across all messages, and a gallery of all photos.

🔒 Everything runs only on your device. The app doesn’t send anything anywhere or post anything online. Your conversations stay with you.


📸 What it looks like

Home screen Search
Главная страница — список чатов Поиск по сообщениям
Gallery Grouped by People
Галерея медиа Группировка по лицам

Screenshots will appear here after you upload files to docs/screenshots/ (see instructions).


⬇️ Download and install

Ready-to-use installers are available on the Releases page (the latest version is at the top).

System File Size How to install
🪟 Windows VkArchiveReader-*.msi ~120 MB Run the file and follow the installation wizard. If Windows displays "SmartScreen," click "More info" → "Run anyway."
🍎 macOS VkArchiveReader-*.dmg ~128 MB Open the image and drag the app to “Applications.” When you launch it for the first time, right-click the icon → “Open” (app not signed by Apple).
🤖 Android VkArchiveReader-android.apk ~14 MB Copy the file to your phone and open it. Allow “installation from unknown sources” if your phone prompts you.

The facial recognition model (~40 MB) is not included in the installer—it is downloaded only once when you run the facial search for the first time. This keeps the installer compact.

System warnings about an “unknown developer” are normal for free apps without a paid digital signature. The installers are built automatically from the source code in this repository (see the section for developers below).


🗂 How to get your VKontakte archive

  1. Open the VK guide: How to get an archive of your data?
  2. Request the download and wait for an email or notification that the archive is ready (this may take several hours or days).
  3. Download the archive. It will be .zip a file or a folder containing a file index.html inside and a directory messages/.
  4. Open the app and drag the folder or .zip into the window—or tap the “Select Archive” button.

Done—the app will read the conversations and display them in a user-friendly format.


🎬 Don’t have your own archive? Try the demo

Don’t want to wait for the archive to load? Just tap “Don’t have your own archive? Open demo data” on the home screen . The app will open a built-in demo archive with several fictional chats, photos, and people, so you can try out all the features: reading, searching, the gallery, and grouping by people.

The demo data is fictional; photos are loaded from public dummy services, so you’ll need an internet connection for the demo.


✨ What the app can do

  • 💬 A list of chats with previews of the latest message and counters for messages and media.
  • 🔀 Sort chats by date, number of messages, number of media files, or name.
  • 🔎 Search by messages—across all conversations or within a single chat, with filters by person/group and by author.
  • 🧵 Read conversations in convenient “bubbles” with emojis and content that loads as you scroll.
  • 🖼 Gallery of all photos—across all chats or in a specific one, with options to set the number of columns, full-screen view, and a filter by format (JPG, PNG, GIF, WebP, MP4 …).
  • ⬇️ Download media—either as a single file or in bulk: from one or multiple chats, with the option to filter by year. On a computer/Android—to a folder (which you can select in settings); in a browser—as a single ZIP archive.
  • 🎧 You can listen to voice messages right in the app (Android and web).
  • 🧑‍🤝‍🧑 Grouping by people (on a computer)—the app automatically detects faces in photos and groups them by person, entirely locally.
  • 💾 Image cache for fast reloading, with customizable size settings.

❓ Frequently Asked Questions

Some photos won’t open—why? Photos in the archive are stored not as files, but as links to VK servers with a limited lifespan. For older archives, some links are no longer accessible—this is a limitation of the data itself, not the app.

Does the app send my chat history to the internet? No. The archive is parsed and grouped by people on your device. Only requests to download the images themselves via their links are sent over the network (just like in a browser).

What’s the best device to use? Any device will work for reading and searching. For grouping by person, you’ll need a computer (Windows/macOS/Linux).



🛠 Documentation for developers and LLM

Below is the technical section: architecture, stack, build, archive format, and how the demo data and face recognition work.

Stack and Platforms

Layer Technology
Language Kotlin Multiplatform
UI Compose Multiplatform (Material 3)
Image Loading Coil 3 on top of Ktor 3 (CIO/OkHttp/JS/Darwin per platform)
DI Koin 4
Face storage (Desktop) SQLite (sqlite-jdbc)
Face ML (Desktop) OpenCV via Bytedeco (YuNet + SFace)
Pagination Custom incremental page-by-page loader (50 messages at a time)
Platform Status
Desktop (macOS/Windows/Linux, JVM) ✅ Folder/ZIP selection + drag-and-drop; face recognition
Android ✅ Open .zip via system file selection
Web (JS / Wasm) ✅ Select extracted folder (webkitdirectory); ZIP and other formats not yet supported
iOS ⚙️ UI is under development; file selection is not yet implemented

Pagination was written manually because AndroidX/Cash App Paging 3 do not support wasmJS, and Web is the target platform. The custom loader ConversationViewModel works on all targets.

Architecture

shared/commonMain/.../ru/normno/vkarchivereader
├── core/            Cp1251 (декодер/энкодер windows-1251), Html (сущности/теги)
├── domain/model/    ChatSummary, Message, Attachment, MediaItem, ChatSortOrder
├── data/
│   ├── parser/      VkArchiveParser — чистый парсинг HTML архива
│   ├── source/      ArchiveSource (expect-доступ к файлам), ArchivePicker (expect),
│   │                DemoArchiveSource (встроенные демо-данные, common)
│   └── repository/  ArchiveRepository — сканирование архива, поиск, чтение страниц
├── face/            Детекция/эмбеддинги/кластеризация лиц (expect/actual)
├── di/              AppModule (Koin)
└── presentation/    welcome / archive / conversation / media / face / components

Data Flow

  1. User selects a folder/zip file → platform-specific ArchiveSource (or built-in DemoArchiveSource).
  2. Two-phase upload for responsiveness with large archives:
    • ArchiveRepository.open() — light pass (≈2 reads per chat): a list of chats with the exact number of messages and previews almost instantly.
    • ArchiveRepository.indexMedia() — Background processing across all pages, filling media counters and the gallery, cooperatively yielding (yield).
  3. Chat messages are loaded page by page as you scroll.
  4. Search (search) re-reads the necessary pages and filters them.

The archive format itself is documented in VK_ARCHIVE_STRUCTURE.md.

⚠️ Media in the archive consists of signed VK links with a limited lifespan; for older archives, some content is no longer available (a placeholder is displayed).

How the demo data is structured

DemoArchiveSource (in data/source, commonMain) — this is ArchiveSource, which generates HTML in exactly the same format as an actual VK upload and encodes it in Windows-1251 via Cp1251.encode. Thanks to this, the demo passes through the same VkArchiveParser/ArchiveRepositoryas the real archive—without a single special case in the rest of the code. The button on WelcomeScreen simply outputs ArchivePickOutcome.Success(DemoArchiveSource()).

  • Cyrillic characters are encoded in CP1251; emojis are written as numeric HTML entities (😀), since CP1251 doesn't support them—the parser converts them back.
  • Photos link to public placeholders (randomuser.me — stable portraits for grouping by faces, picsum.photos — landscapes), so the demo requires an internet connection.
  • The “Memes and Cats” chat intentionally contains 56 posts (> 50) to demonstrate pagination; the “Friends” conversation features multiple authors (for filtering by author and people).
  • Covered by the test DemoArchiveTest (parsing, pagination, authors, media, search).

Grouping by people (Desktop)

Fully local pipeline (nothing leaves the device), launched from the “All Media” screen using the “People” button:

  • Detection: YuNet (OpenCV Zoo, ~340 KB ONNX).
  • Embeddings: SFace (128-dimensional vector; “one person” if cosine proximity > 0.363).
  • Clustering: greedy online clustering (OnlineFaceClusterer) — streaming, without prior knowledge of the number of people.
  • Runtime: OpenCV via Bytedeco. Only native libraries for the current desktop— javacpp.platform in gradle.properties (by default macosx-arm64); for other operating systems, override (windows-x86_64, linux-x86_64, macosx-x86_64). Version pinned to 4.9.0-1.5.10 (in 4.10.0 native videoio on macOS arm64, it references a non-existent libOrbbecSDK.1.9.dylib and drops FaceDetectorYN). Models are downloaded once every ~/.vkarchivereader/models from the LFS endpoint media.githubusercontent.com.
  • Storage: local SQLite (~/.vkarchivereader/faces.db); the photos themselves are not saved—only the link, group, and source chat.

Recognition is not yet available on Android/iOS/Web; expect/actual (createFaceEngine) it can be added later.

Integration test FaceDetectIntegrationTest downloads real models and detects a face in a real portrait. It makes network requests, so by default it is skipped—to run: ./gradlew :shared:jvmTest -DrunFaceIntegration=true.

Building from source

# Desktop (JVM)
./gradlew :desktopApp:run

# Android (debug APK)
./gradlew :androidApp:assembleDebug

# Web
./gradlew :webApp:wasmJsBrowserDevelopmentRun   # Wasm
./gradlew :webApp:jsBrowserDevelopmentRun       # JS

# iOS — открыть ./iosApp в Xcode

# Тесты
./gradlew :shared:jvmTest

Building installers

Installers are built jpackage using the Compose Desktop plugin, so each format is built only on its own OS (it’s not possible to build .msi on macOS).

# macOS  → .dmg   (на macOS)
./gradlew :desktopApp:packageDmg -Pjavacpp.platform=macosx-arm64

# Windows → .msi  (на Windows)
./gradlew :desktopApp:packageMsi -Pjavacpp.platform=windows-x86_64

# Linux  → .deb   (на Linux)
./gradlew :desktopApp:packageDeb -Pjavacpp.platform=linux-x86_64

# Android → .apk
./gradlew :androidApp:assembleDebug

-Pjavacpp.platform specifies which platform’s native OpenCV/OpenBLAS libraries to include in the build. Without it, binaries for all operating systems would be included (~380 MB of extra weight; the DMG would balloon to ~460 MB). With the flag, only the required platform is included—the installer size is reduced by about 3.5 times. When building locally for your own host, you can omit the flag: the platform will be determined automatically.

Final conclusion:

  • desktopApp/build/compose/binaries/main/{dmg,msi,deb}/
  • androidApp/build/outputs/apk/debug/androidApp-debug.apk

CI

.github/workflows/release.yml ’s workflow builds all three installers on the corresponding runners (Windows/macOS/Ubuntu). It is triggered manually (Actions → Run workflow) or via a version tag, and upon pushing the tag, it publishes the artifacts to a GitHub Release:

git tag v1.0.0 && git push origin v1.0.0

License

MIT.

Releases

Open issues

No open issues 🎉

This page was machine-translated from Russian

RU