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 를 이용하는 것이다.