NOMO.asia

게시판의 어떤 글 내에 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 를 이용하는 것이다.