##프로젝트 사전준비##

https://healer4-13.tistory.com/14

 

Go[golang] Youtube api를 사용하여 비공개 재생목록 가져오기 3편(OAuth 인증 준비)

https://healer4-13.tistory.com/12 Go[golang] Youtube api를 사용하여 공개 재생목록 가져오기 1편(API 키 준비) Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. ht

healer4-13.tistory.com

1. 위의 url로 접속 후.

7번에서 사용자를 추가하실 때 본인 프로젝트 계정(healer@gmail.com)과 테스트 계정을 추가해 줍니다. 총 2개 계정 추가.

이유 : 본인 계정에는 2차 인증이 설정되어 있을 거고, 그러면 로그인을 자동화할 수가 없음. 1차 인증만 되어 있는 로그인 계정을 등록해서 접근하려는 의도.

 

클라이언트 ID 만들기

2. 9번에서 애플리케이션 유형을 웹 애플리케이션으로 등록, 승인된 리디렉션 URI에 http://localhost:8080/login/callback를 추가 후 만들기.

설명 : 로그인 후 코드를 받을 때 리디렉션 되는 uri를 설정함. 인증 완료 후 localhost:8080/login/callback을 호출함(리디렉션).

 

유튜브 접근 권한 설정

3. 테스트 계정이 비공개 재생목록에 접근해서 데이터를 가져오기 위해서는 권한을 설정해 주어야 합니다.

유튜브 계정에서 설정 -> 채널상태 및 기능 -> 권환 -> 채널에 접근할 수 있는 권한을 주기 위해 계정 초대 -> 이메일(테스트 계정)과 액세스 권한 설정 후 완료.

 사전준비 완료.

 

 

프로젝트 실행 영상

4. 프로젝트를 실행하면 자동으로 로그인 후 리다이렉트 되어 코드를 추출하고 토큰을 얻습니다. 그리고 기존의 재생목록을 저장한 playlistsLocal.txt파일에 재생목록들과 유튜브에서 가져온 재생들을 비교하여 추가된 재생목록을 업데이트해 줍니다.

A5qhZjetvkY, 03년 박효신 X 03년 박화요비 - 그런일은 ♫♪

ID : A5qhZjetvkY

제목 : 03년 박효신 X 03년 박화요비 - 그런일은 ♫♪

이 추가된 모습을 보실 수 있습니다.

 

github 소스코드

https://github.com/jeetkd/golang_youtube_api/tree/main/youtube_playlists_prj

 

이번에는 OAuth 2.0 클라이언트 ID를 사용해서 자신의 계정에 비공개 재생목록을 가져와 보겠습니다.

👇아래 링크에서 OAuth 2.0 클라이언트 ID를 먼저 발급해주세요.

https://healer4-13.tistory.com/14

 

Go[golang] Youtube api를 사용하여 비공개 재생목록 가져오기 3편(OAuth 인증 준비)

https://healer4-13.tistory.com/12 Go[golang] Youtube api를 사용하여 공개 재생목록 가져오기 1편(API 키 준비) Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. ht

healer4-13.tistory.com

 

Github 코드 : https://github.com/jeetkd/golang_youtube_api/tree/main/private_playlist

 

GitHub - jeetkd/golang_youtube_api: golang youtube api use

golang youtube api use. Contribute to jeetkd/golang_youtube_api development by creating an account on GitHub.

github.com

 

go get "google.golang.org/api/youtube/v3"
go get "golang.org/x/oauth2"

youtube api와 OAuth 2.0 클라이언트 인증을 사용하기 위해서 외부 패키지를 다운로드해주세요.

 

 

package main

import (
	"context"
	"fmt"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/option"
	"google.golang.org/api/youtube/v3"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	//Read json file (json 파일 읽어옴)
	jsonKey, err := ioutil.ReadFile("client.json")
	if err != nil {
		log.Fatalf("Failed to read JSON file: %v", err)
	}

	// Set up the OAuth 2.0 configuration (OAuth 2.0 구성 환경 설정)
	config, err := google.ConfigFromJSON(jsonKey, youtube.YoutubeReadonlyScope)
	if err != nil {
		log.Fatalf("Unable to parse client secret file: %v", err)
	}

	// Create a new OAuth 2.0 client (새로운 OAuth 2.0 클라이언트를 생성 합니다.)
	client := getClient(config)

	// Set up the YouTube API client using the authenticated client (인증된 클라이언트를 사용하여 유튜브 API 클라이언트를 설정)
	service, err := youtube.NewService(context.Background(), option.WithHTTPClient(client))
	if err != nil {
		log.Fatalf("Unable to create YouTube service: %v", err)
	}

	// Retrieve the playlist ID for the private playlist you want to access (접근을 원하는 비공개 재생목록 ID)
	playlistID := "자신의 계정에 비공개 재생목록의 ID를 넣어주세요"

	// Retrieve the playlist items from the private playlist (비공개 재생목록으로부터 재생목록 아이템들을 불러옵니다.)
	playlistItemsCall := service.PlaylistItems.List([]string{"snippet"}).
		PlaylistId(playlistID). // 재생목록 ID 설정
		MaxResults(50)          // Adjust the maximum number of results as per your requirements(가져올 재생목록 item 최대값 설정)

	playlistItemsResponse, err := playlistItemsCall.Do() // "youtube.playlistItems.list" 호출 실행.
	if err != nil {
		log.Fatalf("Unable to retrieve playlist items: %v", err)
	}

	// Process and display the playlist items //가져온 재생목록 아이템들을 제목과 ID 출력
	for _, item := range playlistItemsResponse.Items {
		title := item.Snippet.Title
		videoID := item.Snippet.ResourceId.VideoId
		fmt.Printf("Title: %s, Video ID: %s\n", title, videoID)
	}
}

// getClient retrieves a valid OAuth 2.0 client.(유효한 OAuth 2.0 클라이언트를 불러옵니다.)
// 토큰트로 *http.Client를 생성하고 반환
func getClient(config *oauth2.Config) *http.Client {
	// Retrieve a token, if it exists, or prompts the user to authenticate.
	token := getTokenFromWeb(config)
	return config.Client(context.Background(), token)
}

// getTokenFromWeb uses the provided OAuth 2.0 Config to request a Token. (제공된 Auth 2.0 구성을 사용해서 토큰을 요청)
// It returns the retrieved Token.(유효한 토큰을 반환)
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
	authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
	fmt.Printf("Go to the following link in your browser, then type the "+
		"authorization code: \n%v\n", authURL)

	//토큰 입력
	var code string
	if _, err := fmt.Scan(&code); err != nil {
		log.Fatalf("Unable to read authorization code: %v", err)
	}

	token, err := config.Exchange(context.Background(), code)
	if err != nil {
		log.Fatalf("Unable to retrieve token from web: %v", err)
	}
	return token
}

비공개 재생목록의 아이디와 제목을 가져오는 코드입니다. 하나씩 살펴보겠습니다.

 

config, err := google.ConfigFromJSON(jsonKey, youtube.YoutubeReadonlyScope)

 

- json 파일과 권한 범위를 가지고 *oauth2.Config 구조체를 구성하고 반환함(토큰을 받기 위한 정보가 있음)
jsonKey : 3편에서 다운로드한 json파일
youtube.YoutubeReadonlyScope : 접근 가능한 권한 범위(읽기 전용으로 설정함)

 

service, err := youtube.NewService(context.Background(), option.WithHTTPClient(client))

- Youtube api 사용을 위한 새로운 Service를 생성합니다.
option.WithHTTPClient(client) : 통신을 하기 위해 사용할 HTTP 클라이언트를 지정하는 ClientOption을 리턴.

 

playlistID := "자신의 계정에 비공개 재생목록의 ID를 넣어주세요"

- 접근을 원하는 비공개 재생목록 ID를 넣어주세요.

 

playlistItemsResponse, err := playlistItemsCall.Do()

- "youtube.playlistItems.list"를 실행하고 PlaylistItemListResponse 구조체를 반환합니다.
PlaylistItemListResponse 구조체에 Items에 반환된 재생목록들의 정보가 있습니다.

 

for _, item := range playlistItemsResponse.Items {
		title := item.Snippet.Title
		videoID := item.Snippet.ResourceId.VideoId
		fmt.Printf("Title: %s, Video ID: %s\n", title, videoID)
	}

- resPlaylist.Items를 통해서 반환된 정보를 가져오고 Snippet에서 정보들을 가져옴.
가져온 제목과 비디오 id를 출력합니다.

 

 

1. func getTokenFromWeb(config *oauth2.Config) *oauth2.Token 함수 안에 코드 설명

 

authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)

- 인증코드를 얻기 위한 동의 페이지 url을 반환해 준다. (사용자 인증 후 인증코드 반환)
"state-token" : csrf 방지를 위한 매개변수
oauth2.AccessTypeOffline : 토큰에 관한 설정에 관한 매개변수 (처음에만 인증하고 재인증 필요 없이 리프레쉬 토큰 재발급 가능)

 

token, err := config.Exchange(context.Background(), code)

- 인증코드를 토큰으로 변환해 줍니다.
code : 위에서 발급받고 입력한 인증코드

 

 

2. func getClient(config *oauth2.Config) *http.Client 함수 안에 코드 설명

 

return config.Client(context.Background(), token)

- Client는 제공된 토큰을 사용하여 http 클라이언트를 리턴합니다.
token : 위에서 생성한 토큰

 

실행 화면 설명

 

실행화면 1

1. 빨간색 박스의 url을 복사해서 인터넷 url창에 붙여 넣어서 이동해 주세요.

 

로그인

2. 등록하신 계정으로 로그인해주세요.

 

계속

3. 계속을 눌러주세요.

 

계속

4. 다시 한번 계속을 눌러주세요.

 

토큰 복사

5. 마지막으로 토큰이 발급된 것을 볼 수 있습니다. 빨간색 박스(토큰)를 복사해 주시고 입력해 주시면 돼요.

 

실행 결과

복사하신 토큰을 입력하시면 이렇게 비공개 재생목록의 제목과 ID를 가져옵니다.

6. 파란색 박스 : 토큰

7. 빨간색 박스 : 가져온 제목과 ID

https://healer4-13.tistory.com/12

 

Go[golang] Youtube api를 사용하여 공개 재생목록 가져오기 1편(API 키 준비)

Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. https://console.cloud.google.com/getting-started 링크로 들어가셔서 구글로 로그인 해주세요. 1. 프로젝트 선

healer4-13.tistory.com

**먼저 위의 과정을 5번까지 진행했다는 가정하에 설명하겠습니다.**

 

자신의 계정에 비공개 재생목록 가져오기 위해서는 OAuth 2.0 클라이언트 ID를 생성해 주어야 합니다.

 

API 및 서비스

1. API 및 서비스에서 사용자 인증 정보를 클릭.

 

동의 화면 구성

2. OAuth 2.0 클라이언트 ID를 만들기 위해서는 동의 화면을 먼저 구성해줘야 합니다. 동의 화면 구성을 클릭.

 

동의 화면 구성 (외부)

3. User Type에서 외부를 선택.

 

앱이름, 이메일 추가

4. 앱 이름(test01)과 사용자 지원 이메일(나의 이메일 선택)을 작성.

 

개발자 연락처 정보 입력

5. 개발자 연락처 정보에 이메일 입력. 저장 후 계속.

 

범위 추가

6. 범위 추가 또는 삭제 클릭 -> 유튜브 비공개 사용자 정보에 접근하기 위해 YouTube Data API v3 관련된 범위를 추가 -> 업데이트 클릭.

 

저장 후 계속

7. 위에 보시면 범위가 추가된 것을 볼 수 있습니다. 저장 후 계속 클릭

 

테스트 사용자 추가

8. ADD USERS를 클릭 후 오른쪽에 정보에 접근할 테스트 사용자(로그인할 구글 계정 추가)를 추가해 줍니다. 저장 후 계속 클릭.

 

사용자 인증 정보 만들기

9. 이제 사용자 인증 정보를 만들 수 있습니다.  설명 2로 돌아가셔서 OAuth 클라이언트 ID를 클릭해 주세요.

 

애플리케이션 유형

 

10. 애플리케이션 유형을 선택. 저는 Goland라는 데스크톱 앱에서 접근하기 때문에 데스크 톱 앱으로 선택.

만들기 클릭.

 

클라이언트 보안 비밀번호 json 다운로드

11. 이제 다시 API 및 서비스에 사용자 인증정보로 가시면 OAuth 2.0 클라이언트 ID가 생긴 것을 확인하실 수 있을 겁니다. 클릭해 주시고 클라이언트 보안 비밀번호를 json으로 다운로드해주시고 사용하시면 됩니다.

**api 키를 발급 받지 않으셨다면, 이쪽을 참고하셔서 먼저 발급 받아주세요.**

https://healer4-13.tistory.com/12

 

Go[golang] Youtube api를 사용하여 플레이리스트 가져오기 1편(API 키 준비)

Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다. https://console.cloud.google.com/getting-started 링크로 들어가셔서 구글로 로그인 해주세요. 1. 프로젝트 선

healer4-13.tistory.com

 

Github 코드 : https://github.com/jeetkd/golang_youtube_api/

 

GitHub - jeetkd/golang_youtube_api: golang youtube api use

golang youtube api use. Contribute to jeetkd/golang_youtube_api development by creating an account on GitHub.

github.com

그 다음 유튜브 api를 사용하기 위해서 go get 해줘야 합니다.
현재 프로젝트로 이동하고, go get google.golang.org/api/youtube/v3 명령어로 패키지를 다운로드 해줍니다.

 

package main

import (
	"context"
	"flag"
	"fmt"
	"google.golang.org/api/option"
	"google.golang.org/api/youtube/v3"
	"log"
)

func main() {
	//Set up API Key and playlistID(API 키와 playlistID 설정)
	apiKey := flag.String("api-key", "Put your api key(자신의 api 키를 넣어주세요)", "YouTube API 키")
	playlistID := flag.String("playlist-id", "Put playlist ID(플레이리스트 ID를 넣어주세요)", "재생목록 ID")
	flag.Parse()

	//Create Service(서비스 생성)
	ctx := context.Background()
	service, err := youtube.NewService(ctx, option.WithAPIKey(*apiKey))
	reqPlaylist := service.PlaylistItems.List([]string{"snippet"}). // Set up snippet option
		PlaylistId(*playlistID). //Set up playlistID
		MaxResults(50) //Set up Max Result

	// Do Excute "youtube.playlistItems.list"(PlaylistItemListResponse를 응답으로 받음)
	resPlaylist, err := reqPlaylist.Do()
	if err != nil {
		log.Fatalf("Error fetching playlist items: %v", err.Error())
	}

	// Get playlist Items(재생 목록과 비디오 ID를 가져옴)
	for _, playlistItem := range resPlaylist.Items {
		title := playlistItem.Snippet.Title
		videoId := playlistItem.Snippet.ResourceId.VideoId
		fmt.Printf("%v, (%v)\r\n", title, videoId)
	}

}

apiKey := flag.String 함수에 두번째 인자(Put your api key)에 자신의 api 키를 넣어주시면 됩니다.

playlistID := flag.String 함수에 두번째 인자(Put playlist ID)에 원하시는 재생목록의 ID를 넣어주세요.

 

재생목록 ID

빨간색 박스가 재생목록 ID 입니다.

이제 재생목록을 가져오기 위해서는 Service를 생성해야 하는데요

 

ctx := context.Background()
service, err := youtube.NewService(ctx, option.WithAPIKey(*apiKey))

youtube.NewService(ctx, option.WithAPIKey(*apiKey)) 함수를 사용해서 생성 합니다.

첫 번째 인자는 Context이고, 두 번째 인자는 구글 API 클라이언트에 대한 clientOption 입니다. WithAPIKey를 사용하여 apiKey에 대한 clientOption을 반환해 줍니다.

 

reqPlaylist := service.PlaylistItems.List([]string{"snippet"}). // Set up snippet option
		PlaylistId(*playlistID). //Set up playlistID
		MaxResults(50) //Set up Max Result

https://developers.google.com/youtube/v3/docs/playlists/list?hl=ko 

 

Playlists: list  |  YouTube Data API  |  Google for Developers

Playlists: list 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. API 요청 매개변수와 일치하는 재생목록의 모음을 반환합니다. 예를 들어 인증된 사용자가 보유

developers.google.com

**위 공식 문서 참조.**

반환된 Service를 통해서 List 메소드를 통해 API 응답 하위 속성("snippet")을 셋팅해 줍니다.

PlaylistId(*playlistID) : 재생목록의 리스트를 반환하는 재생목록의 ID를 설정

MaxResults(50) : 반환하는 항목의 수를 설정(0이상 50이하)

 

resPlaylist, err := reqPlaylist.Do()

reqPlaylist.Do() : "youtube.playlistItems.list"를 실행하고 PlaylistItemListResponse 구조체를 반환합니다.

PlaylistItemListResponse 구조체에 Items에 반환된 재생목록들의 정보가 있습니다.

 

for _, playlistItem := range resPlaylist.Items {
		title := playlistItem.Snippet.Title
		videoId := playlistItem.Snippet.ResourceId.VideoId
		fmt.Printf("%v, (%v)\r\n", title, videoId)
	}

resPlaylist.Items를 통해서 반환된 정보를 가져오고 Snippet에서 정보들을 가져옴.

제목과 비디오id를 출력 합니다.

 

결과 화면

 

Youtube api를 사용하기 위해서는 먼저 구글 클라우드 플랫폼에서 프로젝트를 생성해줘야 합니다.

https://console.cloud.google.com/getting-started 링크로 들어가셔서 구글로 로그인 해주세요.

 

프로젝트 선택

1. 프로젝트 선택을 눌러주세요.

 

새 프로젝트

2. 새 프로젝트를 눌러주세요.

 

새 프로젝트 만들기

3. 프로젝트 이름(Test01)을 입력하고, 만들기를 눌러주세요.

 

YouTube Data API v3 검색

4. 파란색 박스를 보시면 프로젝트(Test01)가 생성된 걸 볼 수 있습니다.  Youtube api를 사용하기 위해서 "youtube data api"를 검색하시고 아래 빨간색 박스 YouTube Data API v3를 선택해주세요.

 

YouTube Data API v3 사용

5. YouTube Data API v3를 사용하기 위해서  "사용"을 눌러주세요.

 

사용자 인증 정보 만들기

6. API 키를 얻기 위해서 이제 사용자 인증 정보를 만들기를 눌러주세요.

 

사용자 인증 정보 유형

7. 공개 데이터(공개적인 데이터에 접근하기 위해서)를 선택해 주시고 다음을 눌러주세요.

추가 설명 : 사용자 데이터를 선택하시면 OAuth 인증 방식을 사용해야 하고, 사용자의 데이터에 접근한다(ex : 내 비공개 플레이 리스트).

 

내 사용자 인증 정보(API 키)

8. 이제 API 키가 발급된 걸 볼 수 있습니다. API 키를 복사하시고 완료를 눌러주세요.

 

API 키 확인

9. 사용자 인증 정보를 누르시면 API 키가 1개 생성된 걸 확인할 수 있습니다. API 키 1개를 클릭하시면 키 정보를 확인할 수 있습니다.

https://go.dev/blog/intro-generics

type Ordered interface {
    Integer|Float|~string
}


The expression ~string means the set of all types whose underlying type is string.
~string 표현식은 실제 타입이 string인 모든 타입의 집합을 의미한다.

This includes the type string itself as well as all types declared with definitions such as type MyString string.
이것은 type MyString string와 같은 정의와 함께 선언된 모든 타입들 뿐만 아니라 string타입 자신을 포함합니다.


해석 : type키워드를 사용해서 string을 MyString(Named Type)으로 선언하였다. string과 MyString은 서로 다르다.

 

s1을 string 타입처럼 사용할 수 없다.

 

하지만 ~string을 사용하면 string자신뿐만 아니라 type MyString string로 선언된 타입까지 사용할 수 있다는 뜻이다.

제네릭으로 예제를 만들어보면,

 

제네릭

Integer 인터페이스에 int앞에 tilde(~)를 안 넣어주니 오류가 나온다. MyInt는 Integer를 구현하지 않았다고 나오고 가로 안에 아마 Integer안에 int 앞에 ~를 잃어 버렸다고 한다. Integer 인터페이스 안에 int 앞에 tilde(~) 를 넣어주면 올바르게 작동할 것이다. 이렇게 Integer안에 정의한 자료형들을 underlying type도 허용하고 싶으면 앞에 tilde(~)를 넣어주면 된다.

Close() 메소드를 찾지 못함

go 인 액션 255페이지(ebook) 8장 예제 8.46을 맥북에서 실습중 os.Create()가 *os.File을 f에 반환하는데 f는 Close() 메소드를 찾지 못하고 있어서 이걸로 삽질......

 

https://cs.opensource.google/go/go/+/refs/tags/go1.19.2:src/os/file_posix.go;l=21 

 

https://cs.opensource.google/go/go/+/refs/tags/go1.19.2:src/os/file_posix.go;l=21

 

cs.opensource.google

 

Close 메소드 소스를 보니
5번째 줄에 go:build unix || (js && wasm) || windows 로 되어 있음

아마도 내가 맥북을 써서 darwin 운영체제로 기본값이 되어 있을꺼라 예측하고 내 컴퓨터에서 /usr/local/go/src/os/file_posix.go 파일을 찾음

 

file_posix.go 파일이 무시되고 있음.

'file_posix.go' is ignored by the build tool because of the OS mismatch

file_posix.go가 빌드툴에 의해서 무시되고 있다. OS 미스매치 때문에

라고 바로 나옴 Edit settings를 클릭

OS를 변경

go:build unix || (js && wasm) || windows || linux 에 맞춰서 OS를 windows로 변경 후 OK

그러면 Close() 메소드 사용 가능 해짐

 

 

# 맨 아래 코드 먼저 보시고 설명 읽으시길 추천!!!

 

메서드 집합(method sets)

값의 관점에서 본 메서드 집합
메서드 수신자
T (t T)
*T (t *T)

- 설명

T        (t T) : 값 u는 T이고,  notify메서드에서의 수신자 (u user)는 (t T)를 뜻한다.

*T      (t T) 그리고 (t *T) : &u는 *T이고, notify메서드의 수신자 (u *user) 또는 (u user)는 (t T) 와 (t *T)를 뜻한다.

 

수신자의 관점에서 본 메서드 집합
메서드 수신자
(t T) T와 *T
(t *T) *T

-설명

(t T)        T와 *T  : notify메서드에서의 수신자 (u user)는 (t T)이고, u와 &u는 T와 *T를 뜻한다.

(t *T)      *T  : notify메서드의 수신자 (u *user)는 (t *T)이고, &u는 *T를 뜻한다.

 

 

package main

import "fmt"

 

type notifier interface {

    notify()

}

 

type user struct {

    name  string

    email string

}

 

func (u *user) notify() { // (u *user) 수신자

    fmt.Printf("사용자에게 메일을 전송합니다: %s<%s>\n", u.name, u.email)

}

 

func sendNotification(n notifier) {

    n.notify()

}

func main() {

    u := user{"Bill", "bill@email.com"} // u값

    sendNotification(u) //&u로 전달해야 컴파일 가능

}

 

현재 이코드는 작동하지 않는데 이유는 notifier interface가 nofity() 메서드를 가지고 있는데 

notify메서드의 수신자는 u *user(포인터 수신자)이다. 하지만 main에서 sendNotification 인수로 &u가 아닌 u를 전달하고 있다.

위의 메서드 집합에 따르면 메서드 수신자 (u *user) 포인터 이므로 &u 같이 주소만를 전달할 있다. 

 

출처 : 책. Go 인 액션 132쪽 메서드 집합

+ Recent posts