package youtube import ( "bytes" "encoding/json" "fmt" "net/http" "net/url" "github.com/grafov/m3u8" ) type Client struct { InnertubeClient *InnertubeClient HTTPClient *http.Client } type InnertubeClient struct { Key string `json:"-"` HDRClientName string `json:"-"` HL string `json:"hl,omitempty"` GL string `json:"gl,omitempty"` ClientName string `json:"clientName,omitempty"` ClientVersion string `json:"clientVersion,omitempty"` DeviceModel string `json:"deviceModel,omitempty"` UserAgent string `json:"userAgent,omitempty"` TimeZone string `json:"timeZone,omitempty"` UTCOffsetMins int64 `json:"utcOffsetMinutes,omitempty"` } type innertubeRequest struct { VideoID string `json:"videoId,omitempty"` BrowseID string `json:"browseId,omitempty"` Continuation string `json:"continuation,omitempty"` Context struct { Client InnertubeClient `json:"client"` } `json:"context"` PlaybackContext struct { ContentPlaybackContext struct { HTML5Preference string `json:"html5Preference"` } `json:"contentPlaybackContext"` } `json:"playbackContext,omitempty"` ContentCheckOK bool `json:"contentCheckOk,omitempty"` RacyCheckOk bool `json:"racyCheckOk,omitempty"` Params string `json:"params"` } var ( IOSClient = InnertubeClient{ Key: "AIzaSyAOghZGza2MQSZkY_zfZ370N-PUdXEo8AI", HDRClientName: "5", HL: "en", GL: "US", ClientName: "IOS", ClientVersion: "17.33.2", DeviceModel: "iPhone14,3", UserAgent: "com.google.ios.youtube/17.33.2 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)", TimeZone: "UTC", UTCOffsetMins: 0, } ) var DefaultClient = IOSClient func New() *Client { client := new(Client) client.HTTPClient = &http.Client{} client.InnertubeClient = &DefaultClient return client } func (c Client) GetVideoFromID(id string) (out Video, err error) { uri, _ := url.Parse("https://www.youtube.com/youtubei/v1/player") q := uri.Query() q.Add("key", c.InnertubeClient.Key) uri.RawQuery = q.Encode() reqData := new(innertubeRequest) reqData.Context.Client = *c.InnertubeClient reqData.VideoID = id reqData.ContentCheckOK = true reqData.RacyCheckOk = true reqData.Params = "CgIQBg==" reqData.PlaybackContext.ContentPlaybackContext.HTML5Preference = "HTML5_PREF_WANTS" reqBody, err := json.Marshal(reqData) if err != nil { return } payload := bytes.NewReader(reqBody) req, err := http.NewRequest("POST", uri.String(), payload) if err != nil { fmt.Println(err) return } req.Header.Add("User-Agent", c.InnertubeClient.UserAgent) req.Header.Add("X-YouTube-Client-Name", c.InnertubeClient.HDRClientName) req.Header.Add("X-YouTube-Client-Version", c.InnertubeClient.ClientVersion) req.Header.Add("Content-Type", "application/json") res, err := c.HTTPClient.Do(req) if err != nil { fmt.Println(err) return } defer res.Body.Close() json.NewDecoder(res.Body).Decode(&out) return } func (v Video) GetUrlByItag(itagNo int64) string { for _, format := range v.StreamingData.AdaptiveFormats { if format.Itag == itagNo { return format.URL } } return "" } func (v Video) GetHLSPlaylist(itag string) (out string) { resp, err := http.Get(v.StreamingData.HlsManifestURL) if err != nil { return } defer resp.Body.Close() p, _, err := m3u8.DecodeFrom(resp.Body, true) if err != nil { return } pl := p.(*m3u8.MasterPlaylist) for _, variant := range pl.Variants { if len(variant.Alternatives) > 0 { for _, a := range variant.Alternatives { if a.GroupId == itag { return a.URI } } } } return }