gfycat 동영상 정보를 api token 없이 익명으로 가져오기
Posted 2019. 2. 7. 01:07, Filed under: 개발/JavaScript게시판의 어떤 글 내에 gfycat 주소 형태를 가진 링크가 삽입된 경우,
client 단에서 자바스크립트를 이용하여 자동으로 해당 이미지나 동영상을 동적으로 글에 삽입하는 브라우저 extension 을 만들고 싶었다.
이 과정에서 알게된 것을 정리해보았다.
gfycat api 문서를 좀 읽어보니... 모든 요청에 token이 필요하다고?
gfycat api 문서(https://developers.gfycat.com/api/)를 읽어봤는데, 테스트는 해보지 않았지만 모든 요청에 token 을 넘겨주어야 한다는 것 같다.
동영상 타이틀, 설명과 같은 간단한 동영상 정보를 가져오는 것 조차도 token을 넘겨야 한다는 것 같다.
참고로 Imgur 의 경우 client-id 만 가지고도 이미지 정보 가져오기, 익명으로 업로드, 익명으로 앨범 생성 등 이런저런 요청이 모두 가능하다.
token을 발급받기 위해서는 header 에 client id 와 client secret 을 적어서 api에 요청을 보내야한다.
그런데 client id 는 모두에게 공개되어도 상관 없는 정보지만, client secret 은 비밀키이므로 공개되어서는 안 된다.
대부분의 브라우저 extension 이나 userscript 와 같이 소스코드가 완전 노출되어 있으면서 별도의 서버 없이 client 쪽에서만 돌아가는 코드의 경우, client secret 을 소스코드 내에 삽입해버리면 해당 값이 불특정 다수에게 노출될 수 있다.
이 경우, 선택 가능한 방법은 별도의 서버를 둬서 client secret 을 숨기거나, 아니면 그냥 부작용을 감수하고 client secret 을 노출시키거나, 아니면 별도로 web sdk 접근 권한을 요청하여 부여받는 것 정도인 것 같다.
결국 웹을 뒤지다가 token 발급 없이 적용 가능한 새 방법을 찾아냈다.
익명으로 gfycat 이미지 or 동영상 정보 가져오기
단순히 이미지 or 동영상 정보만을 가져오는 것은 아래에서 소개하는 방법으로 가능하다.
아래 링크로 접속했을 때 내가 원하는 기능이 구현되어 있길래 찾을 수 있었다.
https://www.reddup.co/r/gfycat/comments/a4ii54/problem_with_lowercase_urls/
방법은 단순하다. 아래의 링크에 직접 접속해보면 JSON 형태의 결과를 볼 수 있다.
https://api.gfycat.com/v1test/gfycats/enlightenedpleasedliger
다만 위의 주소에 포함된 test 라는 단어에서 알 수 있는 것처럼 정식 api 는 아닌 것 같다.
단순히 이미지, 동영상 정보만 가져오기 때문인지는 몰라도, client id 나 client secret 모두 필요 없다.
호출 예제는 아래와 같다.
var gfycat_id = "EnlightenedPleasedLiger"; $.ajax({ url:"https://api.gfycat.com/v1test/gfycats/"+gfycat_id, type: "GET", success:function(response){ console.log(response) }, error:function(error){ console.log(error); } });
응답은 아래와 같다.
{ "gfyItem": { "tags": [], "languageCategories": [], "domainWhitelist": [], "geoWhitelist": [], "published": 1, "nsfw": "0", "gatekeeper": 0, "mp4Url": "https://giant.gfycat.com/EnlightenedPleasedLiger.mp4", "gifUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-size_restricted.gif", "webmUrl": "https://giant.gfycat.com/EnlightenedPleasedLiger.webm", "webpUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger.webp", "mobileUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-mobile.mp4", "mobilePosterUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-mobile.jpg", "extraLemmas": "", "thumb100PosterUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-mobile.jpg", "miniUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-mobile.mp4", "gif100px": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-max-1mb.gif", "miniPosterUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-mobile.jpg", "max5mbGif": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-size_restricted.gif", "title": "The perfect cameowflage", "max2mbGif": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-small.gif", "max1mbGif": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-max-1mb.gif", "posterUrl": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-poster.jpg", "languageText": "", "views": 2344494, "userName": "respectmyauth", "description": "", "hasTransparency": false, "hasAudio": false, "likes": "2", "dislikes": "0", "gfyNumber": "503589998", "userDisplayName": "RespectMyAuthoriteh", "userProfileImageUrl": "https://profiles.gfycat.com/13c23cfc2642bf519ae94d3a41982f6710642a8329ae1fe57afd7607c613a5ad.png", "gfyId": "enlightenedpleasedliger", "gfyName": "EnlightenedPleasedLiger", "avgColor": "#B5977A", "width": 640, "height": 800, "frameRate": 30.014025, "numFrames": 428.0, "mp4Size": 1049054, "webmSize": 945225, "createDate": 1544284400, "url": "https://www.instagram.com/p/BrAx26DFsm3/", "source": 1, "content_urls": { "max2mbGif": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-small.gif", "size": 1755832, "height": 250, "width": 200 }, "webp": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger.webp", "size": 3350218, "height": 0, "width": 0 }, "max1mbGif": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-max-1mb.gif", "size": 914896, "height": 200, "width": 160 }, "100pxGif": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-max-1mb.gif", "size": 914896, "height": 200, "width": 160 }, "mobilePoster": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-mobile.jpg", "size": 37312, "height": 800, "width": 640 }, "mp4": { "url": "https://giant.gfycat.com/EnlightenedPleasedLiger.mp4", "size": 1049054, "height": 800, "width": 640 }, "webm": { "url": "https://giant.gfycat.com/EnlightenedPleasedLiger.webm", "size": 945225, "height": 800, "width": 640 }, "max5mbGif": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-size_restricted.gif", "size": 4591628, "height": 312, "width": 250 }, "largeGif": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-size_restricted.gif", "size": 4591628, "height": 312, "width": 250 }, "mobile": { "url": "https://thumbs.gfycat.com/EnlightenedPleasedLiger-mobile.mp4", "size": 1638937, "height": 800, "width": 640 } }, "userData": { "name": "RespectMyAuthoriteh", "profileImageUrl": "https://profiles.gfycat.com/13c23cfc2642bf519ae94d3a41982f6710642a8329ae1fe57afd7607c613a5ad.png", "url": "https://gfycat.com/@respectmyauth", "username": "respectmyauth", "followers": 266, "following": 0, "profileUrl": "", "views": 178945688, "verified": false } } }
만약 gfycat id가 존재하지 않는 것일 경우 아래와 같이 뜬다.
{"errorMessage":"ddddddddddddd does not exist."}
object에 동영상의 raw 주소도 적혀있는데, 동영상 raw 주소를 바로 가져와서 사용하는 것은 gfycat 쪽에서 원하지 않는 방법이라고 한다.
ajax call 에 성공하면 width, height 정보를 가져와서 비율을 계산하거나 높이값에만 + 44px 을 하여 iframe 형태로 삽입하면 되고
혹시라도 ajax call 에 실패하고, does not exist 에 해당하는 에러가 아닌 경우 그냥 임의의 비율로 iframe 을 삽입해버리면 된다.
gfycat 링크 및 id 탐지를 위한 정규표현식
임의의 url이 gfycat 링크에 해당하는지를 확인하고, 해당한다면 gfycat id 를 가져오기 위해 정규표현식을 사용한다.
https://regex101.com/r/YscsiZ/1/
심플하면서 잘 작동한다.
실 사용 예제는 아래와 같다.
var reg = /(gfycat\.com\/(?:\w*\/)*)(\w+)/ // href: 검사 대상 url var res = href.match(reg); if(res){ // gfycat 링크 탐지된 경우 할 일 var gfycat_id = res.pop(); // gfycat id 가져오기 // 이후 gfycat id 를 이용해 할 일을 적으면 됨 $.ajax({ url:"https://api.gfycat.com/v1test/gfycats/"+gfycat_id, type: "GET", success:function(response){ console.log(response) }, error:function(error){ console.log(error); } }); }
iframe 으로 gfycat 동영상 삽입하기
https://gfycat.com/enlightenedpleasedliger 와 같은 링크의 경우, 아래와 같이 삽입하면 된다.
1. 크기 유동형
<div style='position:relative; padding-bottom:calc(이미지_비율_퍼센트% + 44px)'> <iframe src='https://gfycat.com/ifr/enlightenedpleasedliger' frameborder='0' scrolling='no' width='100%' height='100%' style='position:absolute;top:0;left:0;' allowfullscreen></iframe> </div>
크기 유동형의 경우, 위 코드를 둘러싼 element 의 가로 길이에 꽉 차게 iframe 이 특정 비율을 가진채로 삽입되게 된다.
이미지_비율_퍼센트% 에는, 만약 동영상 크기가 16:9 비율일 것이라고 가정하면 56.25% 라고 입력하면 된다.
ajax call 에 성공하여 width, height 로부터 비율을 계산할 수 있는 경우에는 계산된 값을 넣어주면 된다.
2. 크기 고정형
<iframe src='https://gfycat.com/ifr/enlightenedpleasedliger' frameborder='0' scrolling='no' width='가로크기' height='세로크기' allowfullscreen></iframe>
크기 고정형의 경우에는 입력한 가로, 세로 크기로 iframe 이 삽입되게 된다.
api 사용 없이 gfycat 링크 주소만 이용하여 raw 동영상 주소 가져오기 (조건부)
다음으로는 api 를 이용하지 않고, gfycat 링크 주소만 가지고 가능한 방법을 정리해보았다.
gfycat 링크의 경우 lowercase 와 camel case 라는 두가지 형태의 링크가 존재한다. 두 링크 모두 동일한 페이지를 표시한다.
둘의 차이는 gfycat id 가 모두 소문자이냐, 아니면 단어의 첫글자를 대문자로 표시하는 형태이냐 이다.
- camel case link: https://gfycat.com/EnlightenedPleasedLiger
- lowercase link: https://gfycat.com/enlightenedpleasedliger
- camel case 형태의 경우
만약 camel case 형태라면 https://giant.gfycat.com/EnlightenedPleasedLiger.mp4 와 같은 형태로 raw 동영상 주소를 가져올 수 있다.
즉 gfycat 링크 주소만 가지고도 raw 동영상 주소를 찾아 다운받거나, 동영상을 글 내에 video 태그 형태로 삽입할 수 있다.
- lowercase 형태의 경우
하지만 lowercase 의 형태는 https://giant.gfycat.com/enlightenedpleasedliger.mp4 로 접속하면 Access Denied 라고 뜬다.
즉 lowercase 형태 주소의 경우에는 raw 동영상을 바로 찾을 수 없다.
lowercase 를 camel case 로 변환하려면 camel case를 구성하는 모든 단어의 리스트를 가지고 있어야 하는데 사실상 어렵고, 추후 단어가 추가될 때마다 리스트를 갱신해야된다는 문제가 있다.
문제는, gfycat 페이지에서 공유 버튼을 눌렀을 때 뜨는 주소가 lower case 형태라서, 사용자는 대부분 lower case 형태의 주소를 가져온다는 것이다.
다만 iframe 으로 삽입할 때는 camel case 와 lowercase 를 구분하지 않는다.
따라서 그냥 iframe 으로 삽입하면 되는데 문제는 동영상 비율을 가져올 수 없어서, 임의 비율로 설정 시 남는 공간은 검은 여백으로 남는다.
contentWindow 로 이미지 or 동영상의 height 를 가져오면 크기 설정이 가능할 것 같기는 한데 테스트 해보지는 않았다.
결국 가장 어썸한 방법은 api 를 이용하는 것이다.