MyShorts - 개발 마무리와 macOS 앱 패키징 삽질

MyShorts는 ChatGPT가 생성한 쇼츠용 JavaScript 페이지에 Typecast 음성을 입히고, FFmpeg으로 MP4를 인코딩하기 위해 만든 개인용 프로그램이다. 전문 영상 편집기처럼 복잡한 기능을 다루는 것이 아니라, 반복되는 쇼츠 제작 과정을 하나로 묶은 도구라서 현재 필요한 기능도 어느 정도 갖춰진 상태다. 사용하면서 큰 문제가 발생하지 않는다면 이제 새로운 기능을 계속 추가하기보다는 개발을 마무리할 생각이었다.

 

이번에도 마지막으로 눈에 걸리던 JS/MP4 재생 대상 선택을 정리하고, 터미널 대신 Finder에서 실행할 수 있는 macOS 앱으로 패키징하면 끝일 줄 알았다. 그런데 기능 수정은 비교적 순조로웠던 반면, 패키징 과정에서 예상하지 못한 문제들이 이어졌다.

JS/MP4 재생 UI 마무리

MyShorts에는 ChatGPT가 생성한 JavaScript 애니메이션을 확인하는 JS Preview와 실제 인코딩 결과를 확인하는 MP4 Preview가 있다. 두 Preview 모두 재생과 Seek를 지원하지만 공용 재생 버튼을 사용하다 보니, 지금 어떤 화면을 조작하는지 명확하게 구분하기 어려웠다. 그래서 재생 버튼 옆에 JS/MP4 콤보박스를 추가했다. 단순히 선택 항목만 늘리는 것이 아니라, 대상을 바꾸면 이전 화면의 재생을 멈추고 각 재생 위치를 유지하도록 했으며, MP4가 준비되지 않은 상태에서는 잘못된 선택을 하지 못하도록 처리했다. 저장된 MP4가 자동 복원되더라도 사용 중인 JS Preview의 선택 상태를 빼앗지 않도록 한 부분도 중요했다.

 

Codex가 재생 상태 동기화와 관련 검증을 진행했고, macOS에서 콤보박스와 재생 버튼의 외형이 약간 어긋나는 부분도 조정했다. 이렇게 실제 사용에 거슬리던 UI를 정리하고 나니, 이제는 기능 추가보다 안정적으로 쓰는 쪽에 집중해도 되겠다는 생각이 들었다.

PyInstaller onefile의 함정

그다음은 앱 아이콘과 패키징이었다. 기존에는 가상환경에서 python -m myshorts로 실행했지만, 영상 하나 만들 때마다 터미널을 열 필요 없이 아이콘을 더블클릭해서 실행하고 싶었다. 아이콘은 앞서 MyStock에서 사용했던 생성 방식을 참고해 원본 PNG에서 macOS용 ICNS와 Windows용 ICO를 만들었다.

 

문제는 PyInstaller의 첫 결과물이었다. ChatGPT가 준비한 프롬프트를 바탕으로 Codex가 onefile 빌드를 수행했고 테스트도 진행했지만, 완성된 것은 내가 기대한 MyShorts.app이 아닌 단일 Mach-O 실행파일이었다. 실행 가능한 파일을 만드는 데는 성공했지만, Finder에서 일반적인 앱처럼 사용하는 것이 목적이었다는 점을 처음부터 제대로 반영하지 못한 것이다. 빌드가 성공했다고 해서 내가 원하는 결과까지 완성된 것은 아니었다. 결국 MyStock의 실제 macOS 패키징 구성을 다시 확인하고 onedir + BUNDLE 방식으로 방향을 바꾸었다. 처음부터 .app이라는 최종 사용 형태를 명확히 정했더라면 생략할 수 있었던 작업이었다.

macOS .app과 FFmpeg 실행 환경

최종 산출물은 dist/MyShorts.app이었다. 단순히 실행파일에 확장자를 붙인 것이 아니라 Qt WebEngine의 Framework, 보조 프로세스, 각종 리소스를 함께 배치해야 했고, JavaScript Preview가 앱 내부에서도 제대로 작동하는지 확인해야 했다.

 

인코딩도 마찬가지였다. 소스 실행에서는 Python 모듈로 별도 Worker를 띄웠지만, 패키징한 앱에서는 내부 실행파일을 Worker로 다시 호출하도록 경로를 나눴다. 기존의 진행 상태 전달과 취소 처리, 원본 WAV·MP4 보존 동작은 그대로 유지하는 것이 조건이었다. 의외로 신경 쓰였던 부분은 FFmpeg 경로였다. 터미널에서는 Homebrew의 FFmpeg을 쉽게 찾지만 Finder로 실행한 앱은 같은 PATH를 보장하지 않는다. 그래서 macOS 앱에서는 PATH를 우선 확인하고, 찾지 못하면 /opt/homebrew/bin과 /usr/local/bin도 검사하도록 보완했다. FFmpeg과 ffprobe를 앱에 포함한 것은 아니므로 외부 설치는 여전히 필요하다.

 

Codex는 실제 앱을 별도 위치로 복사해 JS 재생과 Seek, MP4 Preview, 별도 Worker 인코딩을 합성 자료로 검증했다. 기존 WAV를 재사용한 인코딩과 원본 파일 보존도 확인했고, Finder와 Dock에 아이콘이 표시되는 것도 점검했다. 약 551MB의 arm64 앱이 나왔으니, 이쯤이면 드디어 끝이라고 생각했다.

macOS Keychain이라는 예상 밖의 변수

그런데 실제 사용자 환경에서 MyShorts.app을 실행하자 macOS가 MyShorts.YouTube.OAuth에 대한 키체인 암호를 요구했다. 기존 Python 실행에서는 사용하던 YouTube 인증 정보인데, 새 앱에서는 접근 확인창이 나타났고 재연결과 연결 해제 과정에서도 문제가 생겼다.

사실 macOS Keychain이 인증 정보를 저장한다는 건 알고 있었지만, 개별 항목에 접근할 수 있는 애플리케이션까지 관리한다는 점은 잘 몰랐다. ChatGPT와 함께 키체인 접근 프로그램을 열었는데 처음에는 iCloud 키체인을 보고 있어 해당 항목을 못 찾았고, 로그인 키체인으로 옮긴 뒤에야 MyShorts.Drive.OAuth와 MyShorts.YouTube.OAuth를 확인했다.

YouTube 항목의 접근 제어를 열어보니 허용된 애플리케이션은 Python.app 하나였다. 기존에는 Python으로 MyShorts를 실행했으니 자연스러운 상태였지만, 별도로 만들어진 MyShorts.app이 같은 인증 정보를 읽으려면 접근 권한을 다시 확인해야 할 수 있었던 것이다.

여기서 또 삽질을 했다. 새 앱의 권한을 정리하다가 기존 Python.app을 목록에서 삭제해 버렸고, 이번에는 python -m myshorts로 실행할 때도 인증 정보에 접근하지 못했다. 앱 하나 편하게 실행하려다 기존 개발 환경까지 건드린 셈이다.

 

두 실행 방식이 같은 Keychain 항목을 사용한다는 것과, macOS가 두 프로그램에 같은 접근 권한을 준다는 것은 별개의 문제였다. 다만 이번 현상의 원인을 완전히 확정하거나 양쪽의 YouTube 인증이 정상 복구된 것까지 확인한 상태는 아니다. 현재 앱의 ad-hoc 서명 때문에 재빌드 후 접근 권한이 어떻게 유지될지도 더 살펴봐야 한다.

개발 마무리와 Windows 패키징

이번 작업으로 JS/MP4 재생 대상 선택과 앱 아이콘을 정리하고, macOS 애플리케이션 패키징까지 마쳤다. Keychain 인증 문제처럼 아직 확인이 필요한 부분은 있지만, 앞으로는 새로운 기능을 계속 추가하기보다 실제 쇼츠 제작에 사용하면서 불편하거나 문제가 발생하는 부분만 수정할 생각이다. 다만 이번 패키징을 진행하면서 한 가지 아쉬운 점이 남았다. Python 실행 환경은 앱 내부에 포함했지만, 정작 영상 인코딩에 필요한 FFmpeg과 ffprobe는 시스템에 별도로 설치된 실행파일을 사용한다는 점이다. 현재 내 Mac에서는 문제가 없지만, 다른 컴퓨터에 앱을 옮긴다면 추가 설치가 필요하다는 이야기다.

 

지금 당장 다시 수정할 생각은 없지만, 나중에 Windows 버전을 패키징할 때는 이 부분도 함께 정리해 볼 생각이다. imageio-ffmpeg 같은 Python 패키지를 활용하면 FFmpeg 실행파일을 앱에 포함할 수 있으니, 사용자가 별도의 도구를 설치하지 않고도 MP4를 인코딩하는 구조를 검토할 수 있을 것 같다. 그리고 이번에 코드를 다시 살펴보니 ffprobe 역시 꼭 유지해야 하는지 의문이 들었다. WAV의 실제 재생시간과 장면 전환 시점은 이미 Python에서 계산하고 있고, ffprobe는 완성된 MP4의 영상·음성 스트림을 검사하는 용도로 사용하고 있었다. 어차피 업로드 전에 영상을 직접 확인하는 만큼, ffprobe 의존성을 제거하고 FFmpeg 자체 검증만 남기는 방향도 검토해 볼 만하다.

 

물론 Python 패키지에 포함된 FFmpeg이 현재 인코딩 기능을 모두 지원하는지, Windows 패키징 환경에서도 정상적으로 작동하는지는 아직 확인하지 않았다. 일단 macOS 버전부터 사용하면서 안정성을 확인하고, Windows 패키징을 진행할 때 FFmpeg 동봉과 ffprobe 제거를 함께 검토할 예정이다. 과연 Windows에서는 별도 설치 없이 MP4 인코딩까지 한 번에 성공할 수 있을까?