개발, 코딩/웹사이트, 앱 개발

TubeFolder! 유튜브 구독리스트와 재생목록을 폴더에 넣어서 관리하자! (Feat. 웹뷰앱 수익 인증)

우주관리자 2024. 9. 24.

웹뷰앱 3개 출시 이후 수익

ChatGPT의 등장으로 많은 기대를 가지고 GPT를 이용한 앱 1개와 GPT에게 코딩을 시켜서 만든 앱 2개를 약 1년 전에 출시하였습니다.

 

수익모델은 단순히 웹페이지에 붙어있는 애드센스 광고와 모바일 앱에서 웹뷰앱으로 돌아갈 때 띄울 수 있는 전면광고와 앱열기 광고가 전부였습니다.

 

그것마저 콘텐츠에 비해 광고가 너무 많다는 신고가 들어가서 자주 정책 위반에 걸리기도 했습니다.

걸릴 때마다 굉장히 힘들게 하나하나 광고를 줄여가며 통과를 시켰는데, 사실 광고가 많이 나오긴합니다.

 

그래도 매달 나가는 AWS Lightsail 서버 비용과 그동안 구글 Ads 에 광고했던 몇십만원 정도는 벌어들였어야 본전인데..

 

오늘 날짜가 2024년 9월 24일로 월말에 가까운 시점에 구글 애드몹 쪽 광고 수익을 인증해보겠습니다.

하루에 천원정도 버는 것 같다.

 

앱 하나당 이정도라면 그나마 좋겠지만..

플랫폼별로 2개씩 출시한 것 합쳐서 총 5개의 앱으로 하루 천원정도

 

그동안 구글 Ads에 광고비로 하루 5천원씩 몇개씩 몇달 돌려서인지 몇십만원 이상 나간걸 생각하면 참 가슴이 아픕니다.

 

 

내가 필요한걸 만들어보자

사실 정책 위반 메일이 올 때를 제외하고는 거의 방치 상태로 1년정도 지난 것 같습니다.

앱개발은 맞지않는 것 같아서 최근에는 간단한 게임을 만들어보려고 유니티를 공부 중인데 이것도 쉽지가 않습니다.

 

그러던 중, 유튜브를 사용하면서 오래 전부터 불편하다고 느꼈던 것이 있었는데,

저처럼 구독리스트의 스크롤이 어마어마한 사람이 또 있을까 싶기도하지만 저는 그냥 좋아요를 누를 일이 있으면 무조건 구독도 함께 눌러버리다보니 지난 번에 대규모로 정리를 했음에도 다시 7~800여개가 넘어가는 구독리스트를 갖고 있는 상태입니다.

 

우측의 스크롤이 매우 작다

 

원하는 구독리스트를 찾기도 어려울 뿐더러, 카테고리별로 분류를 좀 하고 싶은데 희한하게도 현재 유튜브에는 이러한 기능이 없습니다.

 

가장 하고싶은 기능 중 하나가, 영어 공부, 영어 리스닝 채널, 기타 연습, 기타 연주곡, 과학 채널, 미스터리 채널, 교양 채널, 뉴스 등으로 카테고리를 나눠놓고 싶은 것이었습니다.

 

재생목록은 제가 제 개인채널에 공개로 해둔 게임 플레이, 기타 연주 등등을 제외하면 90% 이상이 모두 직장인 밴드용 선곡 리스트 (이게 공연이 끝날 때마다 새로운 재생목록을 만들어서 넣기 때문에 계속 늘어납니다), 좋아하는 음악 모음집 등으로 비공개 생성되어있습니다.

 

대부분 개인용 비공개 재생목록이며 다른 채널의 재생목록을 저장해놓기도 함

 

이러다보니 공개, 비공개 목록 구분도 어렵고, 음악 감상용 목록, 학습용 목록 등의 구분도 어렵습니다.

음악의 경우 특정 그룹의 곡들을 앨범별로 모아두고 싶은데, 재생목록 내에는 곡들만 담을 수 있기 때문에 한 그룹에 여러 앨범이 있는 경우 이것을 묶어놓기도 어렵습니다.

 

그래서 생각한 것이, 재생목록과 구독리스트를 API로 얻어와서 폴더화 시킨 리스트를 만들어서 보여주는 웹사이트를 만들자! 였습니다.

 

잘못된 시작

기억에 남는 것 중 하나가, 크롬 웹브라우저의 확장 프로그램 중 구글 주소록 관리였습니다.

크롬 익스텐션으로 설치해서 필요할 때 아이콘 하나만 클릭하면 구글 로그인을 하고 내 연락처를 불러와서 브라우저상에서 편집을 간편하게 할 수 있는 프로그램이었습니다.

 

사실 지금 생각해보면 이런건 그냥 웹사이트로 이동해서 수행하면 되는 기능이므로 웹확장 프로그램 성격과는 맞지 않는 것인데, 그래서인지 현재는 정책을 준수하지 않았다는 경고가 표시됩니다.

 

그런데 이 방법이 가장 간단해보여서 무작정 GPT에게 물어본 뒤 HTML과 JS로 이루어진 웹 확장 프로그램 초안을 만들게 됩니다.

 

https://youtu.be/20QgcNcMLoE

크롬 웹확장 프로그램 1차 개발 완료!

 

개발자 모드로 로컬에서 기능 구현을 간단히 한 뒤 동작 테스트까지 모두 마쳤으나, 게시를 하기 위해서는 심사가 필요했습니다.

 

결론은 OAuth 동의화면 심사와 확장프로그램 심사 모두 거부 당했습니다.

 

OAuth 2.0 동의화면 심사

일단 요구되는 권한 중 민감한 내용을 포함하므로 인증을 받아야한다고 합니다.

첫번째는 유튜브 데이터 읽기 권한이고 두번째는 여러가지 작업 권한입니다 (댓글, 구독, 구독 취소 등)

 

위의 초안 영상을 보면, 정말 별 생각없이, API가 제공하는 기능인 구독/구독취소 기능을 적극 활용하였습니다.

유튜브 구독리스트를 한꺼번에 지우고 싶다는 생각도 해봤는데 그런 기능이 유튜브 자체적으로는 제공되지 않으니 API를 이용해서 지우면 편리하겠다는 생각에, 주요 기능인 폴더화 보다 일괄 구독 취소 기능에 더 집중을 했던 것 같습니다.

 

여러번 구독과 취소 테스트를 일괄로 하다보니 갑자기 404 에러가 계속 반환되는 일이 발생하였는데, 처음에는 코드 변경이 원인인 줄 알았으나 나중에 파악한 결과, API 쿼리 할당량이 프로젝트 별로 존재한다는 것이었습니다.

 

다른건 문제없으나 일일 쿼리 할당량이 10,000개로 조금 적은 편

 

그래도 벌써 10,000번이나 쿼리했나? 싶었는데, 알고 보니 해당 값은 토큰 단위였고 (쿼리 횟수가 아님) 리스트 조회 등은 1토큰만 사용되는 반면, 구독과 구독 취소는 50토큰이 사용되었던 것입니다.

 

https://developers.google.com/youtube/v3/determine_quota_cost?hl=ko

 

YouTube Data API (v3) - 할당량 계산기  |  Google for Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. YouTube Data API (v3) - 할당량 계산기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 아래 표는 각 API 메서

developers.google.com

 

list는 모두 1이나 대부분의 설정 변경, 추가 등은 50 이상이다.

 

제가 일괄 구독취소와 최근 구독취소 리스트를 로컬로 저장해두었다가 다시 일괄로 재구독하는 기능을 어렵게 구현하고 UI 버그가 너무 많아서 계속 테스트를 했었는데, 당시 3~4개씩 구독취소, 재구독을 반복하였으므로 한번에 150~200 토큰씩 소모를 하고 있었고 50~60번 반복만 해도 바로 일일 할당량을 초과하게 되는 것이었습니다.

 

빠르게 머리를 굴려보니, 이 기능을 오픈하면 나혼자 구독 200개 일괄 취소만 해도 전체 서비스의 하루 분량이 모두 소모되는 것이었습니다.

 

그래서 유료로 돈을 내면 할당량을 늘릴 수 있나 찾아봤지만, 할당량 증가 신청만 가능했고, 복잡한 요구 항목을 다 작성해서 제출했지만 거절당했습니다.

 

프로젝트별로 하루 10,000건이므로 무료로 만들 수 있는 구글 클라우드 프로젝트는 25개였으니 훨씬 더 많으 토큰을 사용할 수는 있었지만, 하나의 웹서비스에 하나의 클라이언트 ID 만으로 동작을 해야하므로 (여러 클라이언트 ID를 미리 등록해두고 전화할 수 있게 구현한다면 불가능은 없겠지만, 그렇게까지 하는 것은 말이 안된다고 생각했습니다) 빠르게 구독 관련 기능은 제거를 시키기로 결정하였습니다.

 

웹스토어 심사

OAuth가 승인이 안되다보니 로컬 개발자모드가 아닌 상태에서는 인증 자체가 되지않았습니다.

사실 OAuth 2.0 클라이언트 ID는 다양한 형식으로 제공됩니다.

당연히 Chrome 확장 프로그램으로 만들었다

 

그런데 크롬 확장 프로그램용으로 만든 OAuth 클라이언트 ID는 리디렉션 URI를 설정할 수가 없고 그러다보니 웹페이지를 통해 인증을 할 때 반드시 등록해야하는 리디렉션 URI 설정이 불가능하니 동작이 되지 않았습니다.

 

모순 덩어리처럼 원인이 원인을 물고 늘어졌습니다.

 

한참을 헤매다보니 웹 애플리케이션 형식으로 만들고 리디렉션 URI를 등록 후 웹확장 프로그램에서 사용하니 동작은 되었으나, 이 URI가 chorme-extension:// 과 같은 주소이므로 결국 로컬 개발자 모드가 아닌 이상 동작이 되지 않았습니다.

 

결국 다 만들어놓고 동작이 되지 않는 상황이 발생되었습니다.

 

거부 사유도 동작이 안되는 내용이 대부분이었습니다 (솔직히 조금 창피했습니다)

약속했지만 동작하지 않았다.

 

 

급선회

다행히 웹확장 프로그램의 기본 구조가 html + js 라서 거의 바로 웹사이트 서비스로 전환이 가능했습니다.

vscode에서 로컬 서버를 돌려서 거의 수정없이 모든 기능이 바로 동작했습니다.

 

이런 상황이라면 현재 웹뷰앱으로 만들었던 기존 앱처럼 어렵지않게 모바일앱으로도 출시가 가능할 것 같습니다.

 

사실 이번에는 웹뷰앱이 아니라 주요 기능들이 Java script로 구현되어있으니 React-native로 온전한 앱을 만들어서 안드로이드와 iOS로 배포를 해볼 계획이었습니다만, 이미 GUI 버그 잡는 것에 거의 3~4일을 잠을 못자고 매달리다보니 너무 지쳐버렸습니다.

 

솔직히 js 문법도 아직 잘 모르고 html, css 등 어떻게 사용해야하는지 제대로 공부를 해본 적이 없는데, 이번에 나온 ChatGPT 4o 덕분에 옆에 지치지 않는 프로그래머 한명 앉혀놓고 계속 말로 조지는(?) 식으로 코드를 만들어낼 수 있었습니다.

 

한가지 문제에 대해 무한 반복되는 경우도 있고 제대로 이해하지 못하는 경우도 많았지만 계속해서 최종 코드를 파일 통째로 넘기면서 구체적인 문제 설명과 내가 원하는 것을 명확히 말해주다보면 결국 원하는 답을 찾을 수 있었던 것 같습니다.

 

어쨌든 생각보다 긴 시간을 버그 수정과 부족하지만 최소한의 디자인을 위해 소비를 한 것 같습니다.

 

거의 동일한 두 페이지 (재생목록, 구독리스트)에 거의 비슷한 함수들이 사용되었는데, 어느 순간부터 조금씩 다른 방식으로 같은 기능을 구현하다보니 나중에는 정말 걷잡을 수 없이 복잡해진 것 같습니다.

리팩토링을 시켜볼까 고민도 해봤지만, 중간중간 계속 코드를 생략하고 알려줘서 저도 모르는 사이에 사라져버리거나 원복된 기능들이 많아서 그런 것들 찾고 다시 구현하는 것이 힘들었습니다.

계속되는 수정과 커밋. 일괄 재구독 기능은 언제 제거했는지 기록이 없다. 헷갈려..

 

1차 완성 및 OAuth 재심사 대기

웹확장 프로그램은 완전히 버리고, 웹서비스용으로 1차 완성을 한 뒤, 클라우드 플레어를 통해 배포를 하였습니다.

GitHub 리포지토리에 파일들을 올려놓고 연결만 해주면 커밋 후 동기화를 할 때마다 자동으로 배포가 되어서 정말 편리한 것 같습니다.

 

매우매우 쉽다.

 

구글 애드센스 승인을 받은 ourhertz.com 도메인이 있으므로 youtubefolder.ourhertz.com 라는 하위 도메인도 바로 광고 게재가 가능하였습니다.

 

내친김에 youtubefolder.com 도메인도 가비아에서 구매한 뒤 리디렉션 되도록 설정하였습니다.

 

https://youtubefolder.com/

 

Document

 

youtubefolder.com

 

 

 

OAuth 심사가 완료되어야 테스트 계정으로 등록해놓은 제 이메일 주소 외에도 사용이 가능해질 것 같습니다.

등록해놓지않은 이메일 주소로 로그인을 해도 안전하지않다는 경고가 표시될 뿐 무시하고 진행하면 정상적인 사용이 가능합니다.

 

간단한 사용 방법

제가 원했던 것처럼, "기타 연습"이라는 폴더를 만들고, 제 구독 리스트를 확인하며 '기타' 로 검색을 한 뒤, 한번에 100개의 결과를 보이게 하고, 전체 선택 -> Save selected to folder 버튼을 눌러서 "기타 연습" 폴더로 일괄 저장을 해봤습니다.

좌측의 사이드 메뉴를 열고, 폴더를 만든 뒤 '기타'로 검색

 

저장이 잘 되었습니다.

 

"영어 공부" 폴더도 만들어서 저장

 

폴더 데이터는 브라우저의 로컬 저장소에 저장이 되는 방식이라, 다른 PC에서 동일 계정으로 로그인을 해도 동기화되지 않습니다.

따라서 사이드바 메뉴에 현재 로컬 저장소의 데이터를 json 방식으로 내보내고 가져올 수 있는 기능을 구현해두었습니다.

 

작업한 PC에서 파일을 내보내고, 다른 PC나 핸드폰에서 가져오면 그대로 사용이 가능합니다.

 

외부 서버 등을 이용해서 동기화를 시킬 수도 있겠지만, 기본적으로 클라이언트 사이드에서 동작되는 html + js 구조라, 모든 소스가 노출이 되므로 외부 데이터 베이스 접근은 사실상 전체 구조를 모두 서버 기반으로 바꾸지 않는 이상 어려울 것 같습니다.

 

https://youtu.be/1WGakwz9oDw

OAuth 인증을 위한 간단한 사용 방법 영상. 구린 디자인. 지금은 조금 더 개선했다.

 

 

수익화 고민

외부 서버에서 js가 돌아가게 구조 변경을 하지않는 이상, 유료 구매 구현 (사실 어떻게 하는지 감도 안옴)은 불가능해보입니다.

 

예를 들어 기본은 폴더 저장 수량을 5개로 제한하고, 수동으로 후원을 받고, 후원을 받은 분들의 이메일을 외부 DB에 저장해놓고, 일부 로직을 통해 외부 DB에 있는 사용자일 경우에만 폴더 저장 수량을 무제한으로 서비스해준다거나 하는 등의 수익화를 상상해봤습니다.

 

그러나 이 경우에도 외부 DB에 js를 통해 접근을 해야하므로 모든 인증 정보가 노출이 되어버리므로 불가능한 방법입니다.

 

기능에 제한이 없는 웹사이트 주소를 별도로 운영하는 것도 말이 안되는 방법입니다.

 

앱의 경우, 아직 해본 적은 없지만 웹뷰앱이 아닌 경우라면 유료화가 가능할 것 같습니다.

그러나 구조 전체를 변경하기 전까진 웹뷰앱 방식만 가능하므로, 결국 광고 수익 외에는 구현할 방법이 없을 것 같습니다.

 

업데이트 계획과 발전된 GPT와의 협업

사용자가 많은 것 같다고 생각이 들면 (과연?) 본격적으로 외부 서버를 사용한 방식으로 전환을 시도해볼 계획입니다.

사실 어떤 구성을 가져야하는지 잘 모르겠지만, GPT에게 물어보면 답이 나올 것입니다ㅎㅎ

 

놀랍게도 기존에 출시한 웹서비스, 웹뷰앱들은 훨씬 더 복잡한 구조로 돌아가고 있습니다.

- https://irisgpt.ourhertz.com

 

IrisGPT Chat Bot AI - Customized Non-Login ChatGPT Service

© 2023 우리들의 주파수 All rights reserved.

irisgpt.ourhertz.com

: 클라우드 플레어로 웹페이지 호스팅, 내부 js 를 통해 실제 GPT를 사용하는 API 호출은 AWS Lambda 함수를 사용하여 구현

 

- https://pastface.ourhertz.com

 

Past Life Face Detector - 전생 얼굴 검출기

지난 시대 인물들의 얼굴 데이터를 활용한 무료 서비스입니다. 이 앱은 재미를 위해 제작된 것이며, 실제 전생의 정보나 신빙성을 가진 결과를 제공하는 것이 아닙니다. 업로드한 얼굴 사진은

pastface.ourhertz.com

- https://famousface.ourhertz.com

 

Celeb Face Match - 셀럽 얼굴 매칭

© 2023 우리들의 주파수 All rights reserved.

famousface.ourhertz.com

: 파이썬 플라스크 웹서버를 구현하고 파이썬 제공 모듈을 이용하여 얼굴 인식 기능을 사용. 도커 이미지로 만든 뒤 AWS Lightsail 서버에서 Ubuntu OS 기반으로 동작시키고 nginx + 유니콘을 통해 웹서버 동작 시킴. https 인증서도 받아서 적용시키고 mysql로 관리자 로그인, 푸시알람을 위한 사용자 디바이스 토큰 저장, 사진 업로드 시 얼굴 인코딩 데이터 생성 후 DB 저장 등등, 정말 굉장히 복잡한 기능들을 수행하고 있는데, 이 모든 것을 GPT에게 물어물어 혼자 만들어내고 구성해냈다는 것이 제가 생각해도 놀라울 뿐입니다.

 

위 서비스를 구현할 때에는 GPT 3.5 터보였던 것으로 기억하는데, 코드의 양이 조금만 많아져도 한번에 입력할 수 있는 양이 적어서 굉장히 힘들었습니다.

 

하지만 지금의 GPT 4o 는 코드를 그냥 파일로 10개까지 던져줄 수가 있기 때문에 정말 빠르게 소통이 가능했습니다.

 

1. 외부 서버 구조로 전환

어떻게든 js 소스를 외부 서버에서 돌아가게 해서 외부 DB를 활용할 수 있는 구조로 전환할 계획입니다.

 

2. 무료 사용자와 유료 사용자 구분

폴더 생성 개수 제한, 광고 제거, 폴더 데이터 외부 서버 저장 등으로 유료 결제를 유도해볼 계획입니다.

유료 결제 시 이메일 기반으로 모든 플랫폼에서 동일하게 적용되게 하려고 합니다.

가격은 500~900원 정도가 어떨까 쓸데없는 고민을 미리 해보고 있습니다.

 

3. 일부 기능 추가

폴더에 일괄 저장 기능은 있는데 일괄 삭제 기능은 없습니다.

자체 게시판 등을 통해 자신만의 폴더 데이터 공유 기능도 있으면 좋을 것 같습니다 (자신이 구독하지않은 채널도 보이게)

 

4. 검색 사이트에 등록 및 홍보

구글 서치 콘솔, 네이버 서치어드바이저 등에 등록 후 구글 Ads 등을 통해 광고를 해보려고 합니다.

 

마무리

힘들었지만 1차 완성이 된 것 같아서 기록 차원에서 남겨보았습니다.

 

아래 링크를 통해 사용을 해보시고 댓글로 의견을 남겨주시면 감사드리겠습니다 :)

승인 전까진 로그인 시 안전하지않다는 경고가 나오니 불안하시다면 승인 이후에 해보시면 됩니다 (언제 정식 승인이 될 지는 모르겠지만)

 

https://youtubefolder.com/

 

YouTube Folder - Login

 

youtubefolder.ourhertz.com

 

 

진행상황 업데이트

OAuth 워크플로우 영상이 모든 내용을 담지 않고 있다고 하여 거부 당했습니다.

확인해보니 최초 로그인 시 권한을 요청받는 화면부터 영상에 남겨야하는 것이었습니다.

저는 이미 권한을 가지고 있었으므로 그 화면이 나오지않았는데 구글 계정 관리에 들어가서 써드파티 권한에 등록된 것을 삭제한 뒤 다시 영상을 찍어서 승인 재요청을 하였습니다.

 

이후 또 거부 당한 이유는, 앱 이름에 구글 제품 이름이 있다는 것이었습니다.

YouTube Folder 라는 이름에 너무 대놓고 YouTube 라는 이름을 사용한 것이 문제가 되었습니다 (지금 생각해보면 너무 당연한데 왜 그랬을까요..)

 

결국 급한 마음에 구매한 youtubefolder.com 도 무쓸모가 되었습니다 (내 돈..)

 

그래서 FolderTube와 TubeFolder 라는 이름 중에서 GPT에게 원어민이 들었을 때 어색하지않은 뉘앙스로 골라달라고 했더니 TubeFolder라고 해서 이렇게 이름을 변경한 뒤 재심사 요청을 하였습니다.

(tubefolder.com 은 이제 급하게 구매하지 않습니다)

 

심사가 완료되면 업데이트 해놓도록 하겠습니다.

 

사실, PocketTube 라는 어마무시한 유튜브 구독리스트 폴더화 프로그램이 크롬 확장 프로그램에 있다는 것을 중간에 알았지만, 그냥 1인 개발 연습이라고 생각하고 계속 진행하였습니다.

 

다시 OAuth 심사 중 조치 필요 사항 발생

이름 변경으로 해결되었나 싶었는데 바로 다시 홈페이지에 로그인 버튼 밖에 없고 어떤 사이트인지 설명이 없다는 이유로 심사가 보류되었습니다.

 

로그인을 해야만 기능을 사용할 수 있어서 어쩔 수 없다고 생각했었지만 (원래는 로그인 버튼도 없이 접속하면 index.html 을 통해 바로 로그인이 되도록 할 생각도 있었습니다) 조치를 해야한다면 어떻게 하는게 좋을까 고민이 필요했습니다.

 

결국 다시 ChatGPT에게 조언을 구했고, 깔끔한 첫화면을 만들어줬습니다.

로그인 이후에 기능들이 보인다는 지적 사항이 마음에 걸려서 아예 기능 버튼을 비활성화 해놓은 상태로 로그인 화면에 미리 배치도 하게 수정하였습니다.

 

 

이미지도 ChatGPT에게 다시 그려달라고 한 뒤 배경 지우는 사이트에서 배경을 지워 타이틀 앞에 붙였습니다.

 

그리고 자바 스크립트 코드가 100% 노출되는 것이 아무래도 마음에 걸려서 코드 난독화 사이트를 찾아서 난독화를 하여 배포하였습니다.

https://obfuscator.io/

 

JavaScript Obfuscator Tool

JavaScript Obfuscator Tool A free and efficient obfuscator for JavaScript (including support of ES2022). Make your code harder to copy and prevent people from stealing your work. This tool is a Web UI to the excellent (and open source) javascript-obfuscato

obfuscator.io

 

document.addEventListener('DOMContentLoaded', function () {
    const storedToken = getCookie('authToken');

    if (!storedToken) {
        alert('Not logged in. Please log in.');
        window.location.href = 'index.html';
        deleteCookie('authToken');
        localStorage.removeItem('userInfo');
        localStorage.removeItem(storageKey_subscriptions);
        localStorage.removeItem(storageKey);
    } else {
        // 토큰이 있는 경우, 사용자의 정보를 불러와서 표시
        fetchUserData(storedToken);
    }
    ....

 

이랬던 코드가,

const _0x3f0a34=_0x1ded;(function(_0x4485a4,_0x5ee5b4){const _0x11b9f6=_0x1ded,_0x3d6664=_0x4485a4();while(!![]){try{const _0x3497b7=-parseInt(_0x11b9f6(0x8c))/0x1+parseInt(_0x11b9f6(0x76))/0x2+-parseInt(_0x11b9f6(0x8b))/0x3*(parseInt(_0x11b9f6(0x8f))/0x4)+-parseInt(_0x11b9f6(0x92))/0x5+-parseInt(_0x11b9f6(0x84))/0x6*(-parseInt(_0x11b9f6(0x77))/0x7)+parseInt(_0x11b9f6(0x83))/0x8+-parseInt(_0x11b9f6(0x8a))/0x9*(-parseInt(_0x11b9f6(0x80))/0xa);if(_0x3497b7===_0x5ee5b4)break;else _0x3d6664['push'](_0x3d6664['shift']());}catch(_0x3dfce8){_0x3d6664['push'](_0x3d6664['shift']());}}}(_0x17b5,0x23524),document[_0x3f0a34(0x7e)]('DOMContentLoaded',function(){const _0x1993af=_0x3f0a34,_0x35c574=document[_0x1993af(0x81)](_0x1993af(0x91)),_0x4936a1=_0x40d148(_0x1993af(0x7b));if(_0x4936a1)window[_0x1993af(0x88)][_0x1993af(0x7d)]='home.html';else{const _0x47efcb=new URLSearchParams(window[_0x1993af(0x88)]['hash'][_0x1993af(0x78)](0x1)),_0x5a2570=_0x47efcb[_0x1993af(0x93)]('access_token');_0x5a2570?(_0x50aa09('authToken',_0x5a2570,0x1),window['location']['href']=_0x1993af(0x94)):_0x32898e();}function _0x32898e(){const _0x4431b9=_0x1993af;_0x35c574['style'][_0x4431b9(0x96)]='block',_0x35c574['addEventListener'](_0x4431b9(0x7f),function(){const _0x3b87fc=_0x4431b9,_0x4cf793=_0x3b87fc(0x90),_0x2b1ea4=_0x3b87fc(0x8d),_0x6617cf=[_0x3b87fc(0x87),_0x3b87fc(0x7c),'https://www.googleapis.com/auth/userinfo.profile']['join']('\x20'),_0x55810b='https://accounts.google.com/o/oauth2/auth?client_id='+_0x4cf793+_0x3b87fc(0x85)+encodeURIComponent(_0x2b1ea4)+'&response_type=token&scope='+encodeURIComponent(_0x6617cf)+_0x3b87fc(0x82);window['location'][_0x3b87fc(0x7d)]=_0x55810b;});}function _0x50aa09(_0x902200,_0x3273b6,_0x158d56){const _0x748846=_0x1993af,_0xbd8868=new Date();_0xbd8868[_0x748846(0x8e)](_0xbd8868['getTime']()+_0x158d56*0x18*0x3c*0x3c*0x3e8);const _0x40e2b3=_0x748846(0x89)+_0xbd8868['toUTCString']();document[_0x748846(0x79)]=_0x902200+'='+_0x3273b6+';'+_0x40e2b3+';path=/;Secure;SameSite=Strict';}function _0x40d148(_0x49c38f){const _0x56c6c1=_0x1993af,_0x14bc86=_0x49c38f+'=',_0x26988c=document[_0x56c6c1(0x79)]['split'](';');for(let _0x38edb4=0x0;_0x38edb4<_0x26988c[_0x56c6c1(0x95)];_0x38edb4++){let _0x3f6207=_0x26988c[_0x38edb4];while(_0x3f6207['charAt'](0x0)=='\x20')_0x3f6207=_0x3f6207[_0x56c6c1(0x7a)](0x1,_0x3f6207[_0x56c6c1(0x95)]);if(_0x3f6207[_0x56c6c1(0x86)](_0x14bc86)==0x0)return _0x3f6207['substring'](_0x14bc86['length'],_0x3f6207['length']);}return null;}}));function _0x1ded(_0x3afef7,_0x5c7342){const _0x17b5cd=_0x17b5();return _0x1ded=function(_0x1ded4b,_0x3cabef){_0x1ded4b=_0x1ded4b-0x76;let _0xd3fa32=_0x17b5cd[_0x1ded4b];return _0xd3fa32;},_0x1ded(_0x3afef7,_0x5c7342);}function _0x17b5(){const _0x3c59e8=['authToken','https://www.googleapis.com/auth/userinfo.email','href','addEventListener','click','4724270QxvjrN','getElementById','&prompt=select_account','75800rJGepN','2526LOZpXS','&redirect_uri=','indexOf','https://www.googleapis.com/auth/youtube.readonly','location','expires=','9cSFneZ','214053jSXqov','104195PdGirh','https://tubefolder.ourhertz.com/index.html','setTime','4hIgWMG','764288698992-7gtl7t71bkl3oog1jjc45eoetk8muhsg.apps.googleusercontent.com','loginButton','1136095joQhxW','get','home.html','length','display','122658uRhJba','70SxbFSE','substr','cookie','substring'];_0x17b5=function(){return _0x3c59e8;};return _0x17b5();}
...

 

이렇게 바뀌었습니다.

 

암호화가 아니므로 마음먹고 복원시키려면 얼마든지 복원이 가능하겠지만, 사실 꼭 숨겨야할 키가 있는 것도 아니라서, 몇 페이지 되지 않는 이 사이트의 소스를 그대로 복사해서 쉽게 도용이 가능한 부분만 최소화 시키려는 목적의 처리라고 생각합니다.

 

OAuth 인증이 되면, 리액트 네이티브로 웹뷰앱 방식으로 기능 제한된 무료 버전과 기능 풀린 유료 버전으로 출시해볼 계획입니다.

 

위에서 이 방식으로는 한 사이트에 대해 외부 DB가 없으면 구분이 불가능하다고 언급했었는데, 생각해보니 웹뷰앱 내에 로컬 파일로 html + js 를 구성하여 패키징하면 아무 문제없이 원하는 기능으로 분리가 가능할 것 같습니다.

 

드디어 OAuth 승인

OAuth 승인!

 

첫 페이지 수정을 하고 재심사를 신청하고 약 2일 정도 지난 뒤 드디어 구글 계정 사용자 정보와 유튜브 재생목록, 구독리스트 정보 읽기 전용 권한에 대해 승인을 받았습니다.

 

이제 로그인 시에 안전하지 않은 사이트라는 경고가 사라지고 업로드한 로고 이미지도 정상적으로 보이게 되었습니다.

 

 

최초 로그인 시에는 위와 같이 유튜브 계정 보기 권한에 기본적으로 체크가 안된 상태입니다.

그냥 계속을 눌러서 권한을 주지 않고 진행하면 아래와 같이 구독리스트와 재생목록을 보려고 할 떄 권한이 부족하다는 경고창이 표시되고 다시 로그인을 하도록 유도해줍니다.

 

다행인 것은, 이렇게 한번 더 로그인을 시도하게 되면, 이번엔 기본적으로 모든 필요한 권한에 대해 동의할 것인지만 묻도록 화면이 바뀝니다.

이젠 계속 버튼만 눌러도 유튜브 정보 읽기 권한이 자동 수락이 된다.

 

이젠 정식으로 운영할 수 있게 되었으니 웹뷰앱으로 만들어서 출시를 해보는 것을 1차 목표로 해야겠습니다.

 

구독리스트가 많고 재생목록을 폴더화해서 사용해보고 싶으신 분들은 가볍게 사용해보시고 피드백 주시면 감사드리겠습니다 :)

반응형