Android version of Mixxxtransfer
  • Kotlin 98.6%
  • Python 1.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
libertin fde52ef915 Implement Android Mixxx transfer and backup
Add native archive import/export, persistent directory settings, SAF pickers, transactional backup and recovery, and foreground progress UI.

Include JVM and Android 13/16 SQLite tests, Python interoperability checks, fixtures, licensing, and setup documentation.
2026-10-02 00:03:12 +09:00
app Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
archive-runtime Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
gradle Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
tools Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
.gitignore Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
build.gradle.kts commit empty Android Studio project 2026-10-01 21:24:07 +09:00
gradle.properties commit empty Android Studio project 2026-10-01 21:24:07 +09:00
gradlew commit empty Android Studio project 2026-10-01 21:24:07 +09:00
gradlew.bat commit empty Android Studio project 2026-10-01 21:24:07 +09:00
LICENSE Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
NOTICE Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
PLAN.md Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
README.md Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00
settings.gradle.kts Implement Android Mixxx transfer and backup 2026-10-02 00:03:12 +09:00

Mixxxtransfer Android

Mixxx 플레이리스트와 오디오·큐·분석 데이터를 .tar로 내보내고 가져오는 Android 앱. Kotlin / Compose로 구현했으며 APK에 Python 런타임을 포함하지 않는다.

지원 범위

  • Android 13(API 33) 이상. 현재 target SDK 36, compile SDK 36.1.
  • Mixxx DB 스키마 39. 버전과 필수 컬럼을 확인하며 다른 스키마에는 쓰지 않는다.
  • Python mixxxtransfer의 포맷 2 내보내기, 포맷 1·2 가져오기. 필수 JSON은 manifest.json, tracks.json, playlists.json; 부가 JSON은 없어도 된다.
  • 플레이리스트, 일반 크레이트, Auto DJ 순서, 히스토리 세션 및 그 참조 트랙.
  • 메타데이터, 큐·핫큐·루프, 메인 큐 캐시, BPM 잠금, beats/keys BLOB과 버전, 압축된 분석 sidecar, 색상·재생 통계. track_analysis.track_id는 위치 ID로 매핑한다.
  • 선택적 오디오 이전, 전체 SHA-256 중복 확인, 하위 폴더 복원, 기존 파일 덮어쓰기 방지.
  • 자동·수동 DB 백업, 목록, 외부 저장, 복원. 기본 최근 5개이며 1~20개로 설정한다.

스마트 크레이트 조건, Auto DJ 재생 진행 상태, 네트워크 동기화는 포함하지 않는다. Google Play 배포는 계획에 없으며 APK로 직접 설치한다.

사용법

  1. Mixxx를 종료한다. 앱은 다른 앱의 실행 상태를 확실하게 확인할 수 없으므로, 작업 시작 화면에서 종료 여부를 직접 확인한다.
  2. 설정에서 모든 파일 접근을 허용한다. 폴더 선택기의 URI 권한과 별개로, 실제 Mixxx DB 및 SQLite journal/WAL을 읽고 쓰는 데 필요하다.
  3. Mixxx 디렉터리와 가져온 오디오 디렉터리를 Android 파일 관리자로 선택하거나 입력한 뒤 저장한다. 기본 Mixxx 위치는 /storage/emulated/0/mixxx, DB는 그 아래 mixxxdb.sqlite, 분석 데이터는 analysis/다. 오디오 기본값은 /storage/emulated/0/Music/mixxxtransfer다. 경로·선택 URI·보관 개수를 DataStore에 저장하므로 재실행 후에도 유지된다.
  4. 내보내기에서 실제 플레이리스트와 포함 옵션을 선택하고 미리보기를 확인한다. 저장 위치는 Android 파일 관리자에서 고른다. 완료 시 출력 파일을 다시 읽어 해시를 검사한다.
  5. 가져오기에서 tar를 선택하고 미리보기를 실행한다. 아카이브와 오디오를 검증한 뒤 기존 트랙과 비교한다. 같은 해시는 기존 트랙을 사용하고 기존 큐를 유지한다. 파일명·크기가 같지만 해시를 확인할 수 없는 경우 개별 선택/모두 추가/모두 건너뜀을 제공한다.
  6. 백업 탭에서 수동 백업·복원·외부 저장을 할 수 있다. 진행 상태는 앱과 선택적 전송 알림에서 확인한다.

DB가 없을 때 빈 DB를 만들지 않는다. Mixxx에서 라이브러리를 초기화하거나 위치를 수정한다. 클라우드 폴더는 Mixxx·오디오 디렉터리로 사용할 수 없다. tar 파일 입출력에는 SAF 제공자를 사용할 수 있다. 오디오 미포함 신규 트랙은 고유한 절대 placeholder 경로로 추가되며 파일이 누락된 상태다.

백업과 중단 복구

DB 백업은 filesDir/backups/에 보관한다. VACUUM INTO로 커밋된 WAL까지 포함한 일관된 스냅샷을 만들고 무결성·해시를 확인한 뒤 보관 개수를 정리한다. 가져오기와 복원 전에는 자동 백업이 성공해야 쓰기를 시작한다.

복원은 현재 DB의 트랜잭션 안에서 테이블 내용을 되돌린다. 열린 DB 파일을 교체하거나 WAL을 삭제하지 않는다. 백업의 원래 경로·해시·테이블 정의가 일치해야 한다. DB 백업에는 음악과 analysis/ 파일이 없다. 복원 시 해당 파일은 현재 상태로 유지되므로 백업 시점의 파일이 남아 있어야 정상 재생된다. 앱 삭제 전 필요한 백업은 외부에 저장한다.

작업은 한 번에 하나씩 foreground service에서 실행한다. 회전·백그라운드 전환 후에도 진행 상태를 유지하며 취소·서비스 시간 제한을 처리한다. 프로세스 종료 후 작업을 자동 재실행하지 않는다. filesDir/operations/<UUID>/journal.json과 같은 트랜잭션에 저장한 mixxxtransfer_operations의 커밋 표식을 비교해 중단된 작업을 정리한다. 이 표식용 테이블 외에는 Mixxx 스키마를 생성하거나 업그레이드하지 않는다. 이미 커밋된 DB를 과거 백업으로 자동 덮어쓰지 않는다.

정리 시 DB가 참조하는 파일은 유지하고, 이번 작업이 만든 파일임을 파일 ID와 해시로 확인한 경우에만 삭제한다. 교체·수정·부분 저장된 파일 또는 소유권을 확인할 수 없는 파일은 보존하고 preserved-files.json으로 기록한다. 디버그 APK에서는 다음 명령으로 기록을 확인할 수 있다.

adb shell run-as club.erpin.mixxxtransfer ls files/operations
adb shell run-as club.erpin.mixxxtransfer cat files/operations/작업UUID/preserved-files.json

아카이브는 앱 내부 작업 폴더에서 먼저 검사한다. 절대 경로·경로 탈출·링크·중복 엔트리· 누락 참조·잘린 tar·오디오 해시 불일치를 거부한다. 상한은 tar/총 payload 16 GiB, 오디오 항목 2 GiB, JSON 항목 32 MiB, 분석/BLOB 항목 64 MiB, 항목 25만개, 트랙 10만개다. 작업 폴더에는 tar와 추출 payload를 위한 여유 공간이 필요하다.

빌드와 검증

JDK 21 및 Android SDK 36.1을 준비하고 local.properties에 SDK 위치를 설정한다.

./gradlew :app:assembleDebug :app:lintDebug :app:testDebugUnitTest
python3 tools/check_interop.py

Python 상호 호환 스크립트는 저장소 루트의 mixxxtransfer/에 원본 Python 프로젝트의 로컬 사본이 있어야 실행할 수 있다. 이 참조 사본은 Git에서 제외한다. Android 빌드와 JVM/Robolectric 테스트는 커밋된 소스 및 합성 fixture를 사용한다.

설치용 디버그 APK: app/build/outputs/apk/debug/app-debug.apk. archive-runtime 모듈은 Commons Compress와 그 의존성을 앱 전용 패키지로 옮긴다. Android 16 시스템의 다른 버전 tar 클래스와 충돌하지 않게 하기 위한 구성이다.

테스트는 합성 Python fixture와 실제 SQLite를 사용해 양방향 아카이브, NULL·빈 BLOB·0값, ID 매핑, 반복 가져오기, 충돌 선택, 메타데이터만 가져오기, WAL 백업, 복원 전 백업, SQL 실패·취소 롤백, 중단 복구, 파일 교체 보호, 악성 tar를 검증한다. Robolectric의 Android 13·16 네이티브 SQLite에도 같은 테스트를 실행한다. 연결된 Android 기기가 있을 때는 ./gradlew :app:connectedDebugAndroidTest를 실행할 수 있다.

실제 Android Mixxx 기기에서 폴더 선택·권한·알림·대용량 이전·재검색까지의 검증은 아직 남아 있다. 배포용 릴리스 서명은 이 저장소에 포함하지 않았다. Android Studio의 Generate Signed APK에서 사용자 소유 키를 사용하고, 업데이트마다 같은 패키지·서명 키를 유지하고 versionCode를 올린다. 같은 서명으로 업데이트하면 DataStore 설정이 유지된다.

라이선스

Python 원본과 동일한 GPL-2.0-only. LICENSE 및 NOTICE를 참고한다. 앱과 런처 아이콘은 mixxxtransfer/mixxxtransfer/res/icon.png 원본을 사용한다. 구현 계획과 남은 실제 기기 검증 항목은 PLAN.md에 기록한다.