Go용 Google API 클라이언트 라이브러리를 사용하는 다음 코드 샘플은 YouTube Data API에 사용할 수 있습니다. 이러한 코드 샘플은 GitHub의 YouTube API 코드 샘플 저장소에 있는 go
폴더에서 다운로드할 수 있습니다.
요청 인증
이 코드 샘플은 OAuth 2.0 승인을 수행하기 위해 에는 승인 사용자 인증 정보가 포함됩니다. 파일이 없으면 스크립트는 브라우저를 열고 응답을 기다립니다. 그런 다음 반환된 사용자 인증 정보를 로컬에 저장합니다.
package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net" "net/http" "net/url" "os" "os/exec" "os/user" "path/filepath" "runtime" "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" ) // This variable indicates whether the script should launch a web server to // initiate the authorization flow or just display the URL in the terminal // window. Note the following instructions based on this setting: // * launchWebServer = true // 1. Use OAuth2 credentials for a web application // 2. Define authorized redirect URIs for the credential in the Google APIs // Console and set the RedirectURL property on the config object to one // of those redirect URIs. For example: // config.RedirectURL = "http://localhost:8090" // 3. In the startWebServer function below, update the URL in this line // to match the redirect URI you selected: // listener, err := net.Listen("tcp", "localhost:8090") // The redirect URI identifies the URI to which the user is sent after // completing the authorization flow. The listener then captures the // authorization code in the URL and passes it back to this script. // * launchWebServer = false // 1. Use OAuth2 credentials for an installed application. (When choosing // the application type for the OAuth2 client ID, select "Other".) // 2. Set the redirect URI to "urn:ietf:wg:oauth:2.0:oob", like this: // config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob" // 3. When running the script, complete the auth flow. Then copy the // authorization code from the browser and enter it on the command line. const launchWebServer = false const missingClientSecretsMessage = ` Please configure OAuth 2.0 To make this sample run, you need to populate the client_secrets.json file found at: %v with information from the {{ Google Cloud Console }} {{ https://cloud.google.com/console }} For more information about the client_secrets.json file format, please visit: https://developers.google.com/api-client-library/python/guide/aaa_client_secrets ` // getClient uses a Context and Config to retrieve a Token // then generate a Client. It returns the generated Client. func getClient(scope string) *http.Client { ctx := context.Background() b, err := ioutil.ReadFile("client_secret.json") if err != nil { log.Fatalf("Unable to read client secret file: %v", err) } // If modifying the scope, delete your previously saved credentials // at ~/.credentials/youtube-go.json config, err := google.ConfigFromJSON(b, scope) if err != nil { log.Fatalf("Unable to parse client secret file to config: %v", err) } // Use a redirect URI like this for a web app. The redirect URI must be a // valid one for your OAuth2 credentials. config.RedirectURL = "http://localhost:8090" // Use the following redirect URI if launchWebServer=false in oauth2.go // config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob" cacheFile, err := tokenCacheFile() if err != nil { log.Fatalf("Unable to get path to cached credential file. %v", err) } tok, err := tokenFromFile(cacheFile) if err != nil { authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline) if launchWebServer { fmt.Println("Trying to get token from web") tok, err = getTokenFromWeb(config, authURL) } else { fmt.Println("Trying to get token from prompt") tok, err = getTokenFromPrompt(config, authURL) } if err == nil { saveToken(cacheFile, tok) } } return config.Client(ctx, tok) } // startWebServer starts a web server that listens on http://localhost:8080. // The webserver waits for an oauth code in the three-legged auth flow. func startWebServer() (codeCh chan string, err error) { listener, err := net.Listen("tcp", "localhost:8090") if err != nil { return nil, err } codeCh = make(chan string) go http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { code := r.FormValue("code") codeCh <- code // send code to OAuth flow listener.Close() w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "Received code: %v\r\nYou can now safely close this browser window.", code) })) return codeCh, nil } // openURL opens a browser window to the specified location. // This code originally appeared at: // http://stackoverflow.com/questions/10377243/how-can-i-launch-a-process-that-is-not-a-file-in-go func openURL(url string) error { var err error switch runtime.GOOS { case "linux": err = exec.Command("xdg-open", url).Start() case "windows": err = exec.Command("rundll32", "url.dll,FileProtocolHandler", "http://localhost:4001/").Start() case "darwin": err = exec.Command("open", url).Start() default: err = fmt.Errorf("Cannot open URL %s on this platform", url) } return err } // Exchange the authorization code for an access token func exchangeToken(config *oauth2.Config, code string) (*oauth2.Token, error) { tok, err := config.Exchange(oauth2.NoContext, code) if err != nil { log.Fatalf("Unable to retrieve token %v", err) } return tok, nil } // getTokenFromPrompt uses Config to request a Token and prompts the user // to enter the token on the command line. It returns the retrieved Token. func getTokenFromPrompt(config *oauth2.Config, authURL string) (*oauth2.Token, error) { var code string fmt.Printf("Go to the following link in your browser. After completing " + "the authorization flow, enter the authorization code on the command " + "line: \n%v\n", authURL) if _, err := fmt.Scan(&code); err != nil { log.Fatalf("Unable to read authorization code %v", err) } fmt.Println(authURL) return exchangeToken(config, code) } // getTokenFromWeb uses Config to request a Token. // It returns the retrieved Token. func getTokenFromWeb(config *oauth2.Config, authURL string) (*oauth2.Token, error) { codeCh, err := startWebServer() if err != nil { fmt.Printf("Unable to start a web server.") return nil, err } err = openURL(authURL) if err != nil { log.Fatalf("Unable to open authorization URL in web server: %v", err) } else { fmt.Println("Your browser has been opened to an authorization URL.", " This program will resume once authorization has been provided.\n") fmt.Println(authURL) } // Wait for the web server to get the code. code := <-codeCh return exchangeToken(config, code) } // tokenCacheFile generates credential file path/filename. // It returns the generated credential path/filename. func tokenCacheFile() (string, error) { usr, err := user.Current() if err != nil { return "", err } tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials") os.MkdirAll(tokenCacheDir, 0700) return filepath.Join(tokenCacheDir, url.QueryEscape("youtube-go.json")), err } // tokenFromFile retrieves a Token from a given file path. // It returns the retrieved Token and any read error encountered. func tokenFromFile(file string) (*oauth2.Token, error) { f, err := os.Open(file) if err != nil { return nil, err } t := &oauth2.Token{} err = json.NewDecoder(f).Decode(t) defer f.Close() return t, err } // saveToken uses a file path to create a file and store the // token in it. func saveToken(file string, token *oauth2.Token) { fmt.Println("trying to save token") fmt.Printf("Saving credential file to: %s\n", file) f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Fatalf("Unable to cache oauth token: %v", err) } defer f.Close() json.NewEncoder(f).Encode(token) }
재생목록 나열
이 코드 샘플은 API의 playlists.list
메서드를 호출합니다. 명령줄 플래그를 사용하여
다음 예와 같이 요청에서 사용할 매개변수를 정의합니다.
# Retrieve playlists for a specified channel go run playlists.go oauth.go errors.go --channelId=UC_x5XG1OV2P6uZZ5FSM9Ttw # Retrieve authenticated user's playlists go run playlists.go oauth.go errors.go --mine=true
package main import ( "flag" "fmt" "log" "google.golang.org/api/youtube/v3" ) var ( method = flag.String("method", "list", "The API method to execute. (List is the only method that this sample currently supports.") channelId = flag.String("channelId", "", "Retrieve playlists for this channel. Value is a YouTube channel ID.") hl = flag.String("hl", "", "Retrieve localized resource metadata for the specified application language.") maxResults = flag.Int64("maxResults", 5, "The maximum number of playlist resources to include in the API response.") mine = flag.Bool("mine", false, "List playlists for authenticated user's channel. Default: false.") onBehalfOfContentOwner = flag.String("onBehalfOfContentOwner", "", "Indicates that the request's auth credentials identify a user authorized to act on behalf of the specified content owner.") pageToken = flag.String("pageToken", "", "Token that identifies a specific page in the result set that should be returned.") part = flag.String("part", "snippet", "Comma-separated list of playlist resource parts that API response will include.") playlistId = flag.String("playlistId", "", "Retrieve information about this playlist.") ) func playlistsList(service *youtube.Service, part string, channelId string, hl string, maxResults int64, mine bool, onBehalfOfContentOwner string, pageToken string, playlistId string) *youtube.PlaylistListResponse { call := service.Playlists.List(part) if channelId != "" { call = call.ChannelId(channelId) } if hl != "" { call = call.Hl(hl) } call = call.MaxResults(maxResults) if mine != false { call = call.Mine(true) } if onBehalfOfContentOwner != "" { call = call.OnBehalfOfContentOwner(onBehalfOfContentOwner) } if pageToken != "" { call = call.PageToken(pageToken) } if playlistId != "" { call = call.Id(playlistId) } response, err := call.Do() handleError(err, "") return response } func main() { flag.Parse() if *channelId == "" && *mine == false && *playlistId == "" { log.Fatalf("You must either set a value for the channelId or playlistId flag or set the mine flag to 'true'.") } client := getClient(youtube.YoutubeReadonlyScope) service, err := youtube.New(client) if err != nil { log.Fatalf("Error creating YouTube client: %v", err) } response := playlistsList(service, "snippet,contentDetails", *channelId, *hl, *maxResults, *mine, *onBehalfOfContentOwner, *pageToken, *playlistId) for _, playlist := range response.Items { playlistId := playlist.Id playlistTitle := playlist.Snippet.Title // Print the playlist ID and title for the playlist resource. fmt.Println(playlistId, ": ", playlistTitle) } }
내 업로드 검색
이 코드 샘플은 API의 playlistItems.list
메서드를 호출하여
요청과 관련된 채널에 업로드된 동영상 이 코드는 channels.list
도 호출합니다.
mine
매개변수가 true
로 설정된 메서드를 사용하여
채널에 업로드된 동영상
package main import ( "fmt" "log" "google.golang.org/api/youtube/v3" ) // Retrieve playlistItems in the specified playlist func playlistItemsList(service *youtube.Service, part string, playlistId string, pageToken string) *youtube.PlaylistItemListResponse { call := service.PlaylistItems.List(part) call = call.PlaylistId(playlistId) if pageToken != "" { call = call.PageToken(pageToken) } response, err := call.Do() handleError(err, "") return response } // Retrieve resource for the authenticated user's channel func channelsListMine(service *youtube.Service, part string) *youtube.ChannelListResponse { call := service.Channels.List(part) call = call.Mine(true) response, err := call.Do() handleError(err, "") return response } func main() { client := getClient(youtube.YoutubeReadonlyScope) service, err := youtube.New(client) if err != nil { log.Fatalf("Error creating YouTube client: %v", err) } response := channelsListMine(service, "contentDetails") for _, channel := range response.Items { playlistId := channel.ContentDetails.RelatedPlaylists.Uploads // Print the playlist ID for the list of uploaded videos. fmt.Printf("Videos in list %s\r\n", playlistId) nextPageToken := "" for { // Retrieve next set of items in the playlist. playlistResponse := playlistItemsList(service, "snippet", playlistId, nextPageToken) for _, playlistItem := range playlistResponse.Items { title := playlistItem.Snippet.Title videoId := playlistItem.Snippet.ResourceId.VideoId fmt.Printf("%v, (%v)\r\n", title, videoId) } // Set the token to retrieve the next page of results // or exit the loop if all results have been retrieved. nextPageToken = playlistResponse.NextPageToken if nextPageToken == "" { break } fmt.Println() } } }
키워드로 검색
이 코드 샘플은 API의 search.list
메서드를 호출하여 관련된 검색 결과를 검색합니다.
특정 키워드로 광고를 게재할 수 있습니다.
package main import ( "flag" "fmt" "log" "net/http" "google.golang.org/api/googleapi/transport" "google.golang.org/api/youtube/v3" ) var ( query = flag.String("query", "Google", "Search term") maxResults = flag.Int64("max-results", 25, "Max YouTube results") ) const developerKey = "YOUR DEVELOPER KEY" func main() { flag.Parse() client := &http.Client{ Transport: &transport.APIKey{Key: developerKey}, } service, err := youtube.New(client) if err != nil { log.Fatalf("Error creating new YouTube client: %v", err) } // Make the API call to YouTube. call := service.Search.List("id,snippet"). Q(*query). MaxResults(*maxResults) response, err := call.Do() handleError(err, "") // Group video, channel, and playlist results in separate lists. videos := make(map[string]string) channels := make(map[string]string) playlists := make(map[string]string) // Iterate through each item and add it to the correct list. for _, item := range response.Items { switch item.Id.Kind { case "youtube#video": videos[item.Id.VideoId] = item.Snippet.Title case "youtube#channel": channels[item.Id.ChannelId] = item.Snippet.Title case "youtube#playlist": playlists[item.Id.PlaylistId] = item.Snippet.Title } } printIDs("Videos", videos) printIDs("Channels", channels) printIDs("Playlists", playlists) } // Print the ID and title of each result in a list as well as a name that // identifies the list. For example, print the word section name "Videos" // above a list of video search results, followed by the video ID and title // of each matching video. func printIDs(sectionName string, matches map[string]string) { fmt.Printf("%v:\n", sectionName) for id, title := range matches { fmt.Printf("[%v] %v\n", id, title) } fmt.Printf("\n\n") }
동영상 업로드
이 코드 샘플은 API의 videos.insert
메서드를 호출하여 채널에 동영상을 업로드합니다.
요청 관련 ID입니다.
package main import ( "flag" "fmt" "log" "os" "strings" "google.golang.org/api/youtube/v3" ) var ( filename = flag.String("filename", "", "Name of video file to upload") title = flag.String("title", "Test Title", "Video title") description = flag.String("description", "Test Description", "Video description") category = flag.String("category", "22", "Video category") keywords = flag.String("keywords", "", "Comma separated list of video keywords") privacy = flag.String("privacy", "unlisted", "Video privacy status") ) func main() { flag.Parse() if *filename == "" { log.Fatalf("You must provide a filename of a video file to upload") } client := getClient(youtube.YoutubeUploadScope) service, err := youtube.New(client) if err != nil { log.Fatalf("Error creating YouTube client: %v", err) } upload := &youtube.Video{ Snippet: &youtube.VideoSnippet{ Title: *title, Description: *description, CategoryId: *category, }, Status: &youtube.VideoStatus{PrivacyStatus: *privacy}, } // The API returns a 400 Bad Request response if tags is an empty string. if strings.Trim(*keywords, "") != "" { upload.Snippet.Tags = strings.Split(*keywords, ",") } call := service.Videos.Insert("snippet,status", upload) file, err := os.Open(*filename) defer file.Close() if err != nil { log.Fatalf("Error opening %v: %v", *filename, err) } response, err := call.Media(file).Do() handleError(err, "") fmt.Printf("Upload successful! Video ID: %v\n", response.Id) }