nigonigo

package module
v0.0.0-...-c7ed0a0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2025 License: MIT Imports: 22 Imported by: 0

README

niconico API client for Golang

Build Status Go Reference license

Experimental implementation of niconico API client for Golang.

Features

  • Login/Logout
  • Search
  • MyList
  • Ranking
  • Comments (read only)
  • Download video

Usage

T.B.D.

func main() {
	client := nigonigo.NewClient()

	contentID := "sm9"
	session, err := client.CreateVideoSession(contentID)
	if err != nil {
		log.Fatalf("Failed to create session: %v", err)
	}

	out, _ := os.Create(contentID + "." + session.FileExtension())
	defer out.Close()
	err = client.Download(context.Background(), session, out)
	if err != nil {
		log.Fatalf("Failed to download: %v", err)
	}
	log.Println("ok")
}
Command line tool:

install:

go install github.com/binzume/nigonigo/cmd/nigo@latest

usage:

nigo search "ねこ"
nigo search -t "MMD 初音ミク"
nigo search -sort "-viewCounter" -limit 3  -t "ニコニコ技術部"
nigo search -series 96269
nigo search -id sm9
nigo ranking cooking
nigo auth -i "YOUR_MAILADDRESS"
 Password: ********
nigo download sm9
open sm9.mp4

License

MIT License

Documentation

Overview

niconico client for Golang.

https://www.nicovideo.jp/

Index

Constants

View Source
const (
	RankingAll             RankingGenre = "all"
	RankingHotTopic        RankingGenre = "hot-topic"
	RankingAnimal          RankingGenre = "animal"
	RankingCooking         RankingGenre = "cooking"
	RankingSports          RankingGenre = "sports"
	RankingTechnologyCraft RankingGenre = "technology_craft"
	RankingAnime           RankingGenre = "anime"
	RankingGame            RankingGenre = "game"
	RankingOther           RankingGenre = "other"

	Ranking24H  RankingTerm = "24h"
	RankingHour RankingTerm = "hour"
)

Variables

View Source
var (
	AuthenticationRequired = errors.New("authentication required")
	NotFound               = errors.New("not exist")
	InvalidResponse        = errors.New("invalid response received")
)

errors

View Source
var RequestLogger *log.Logger = nil
View Source
var UserAgent = "Mozilla/5.0 Nigonigo/1.0"

Functions

func NewHttpClient

func NewHttpClient() (*http.Client, error)

Types

type AccountStatus

type AccountStatus struct {
	Area     string `json:"area"`
	Timezone string `json:"timezone"`
	Language string `json:"language"`
	Locale   string `json:"locale"`
	UserID   string `json:"userId"`
	Nickname string `json:"nickname"`

	Description string `json:"description"`

	HasPremiumOrStrongerRights      bool `json:"hasPremiumOrStrongerRights"`
	HasSuperPremiumOrStrongerRights bool `json:"hasSuperPremiumOrStrongerRights"`
	IsExplicitlyLoginable           bool `json:"isExplicitlyLoginable"`

	Premium struct {
		Type string `json:"type"`
	} `json:"premium"`

	Icons struct {
		Urls map[string]string `json:"urls"` // "50x50", "150x150"
	} `json:"icons"`

	Existence map[string]any `json:"existence"` // residence, birthdat, sex
	Contacts  map[string]any `json:"contacts"`  // emails
}

type BaseVideoInfo

type BaseVideoInfo struct {
	ContentID   string `json:"id"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Duration    int    `json:"duration"`

	RegisteredAt string `json:"registeredAt"`
	Count        struct {
		View    int `json:"view"`
		Mylist  int `json:"mylist"`
		Comment int `json:"comment"`
	} `json:"count"`
	Thumbnail struct {
		Url string `json:"url"`
	} `json:"thumbnail"`
}

type ChannelInfo

type ChannelInfo struct {
	ID          string
	Name        string
	Description string
}

type Client

type Client struct {
	HttpClient *http.Client
	Session    *NicoSession
}

func NewClient

func NewClient() *Client

func (*Client) AddMyListItem

func (c *Client) AddMyListItem(mylistId, contentID, description string) error

func (*Client) CreateMyList

func (c *Client) CreateMyList(mylist *MyList) error

func (*Client) CreateVideoSession

func (c *Client) CreateVideoSession(contentID string) (VideoSession, error)

func (*Client) CreateVideoSessionFromVideoData

func (c *Client) CreateVideoSessionFromVideoData(data *VideoData) (VideoSession, error)

func (*Client) DeleteMyList

func (c *Client) DeleteMyList(mylistId string) error

func (*Client) DeleteMyListItem

func (c *Client) DeleteMyListItem(mylistId string, itemID string) error

func (*Client) Download

func (c *Client) Download(ctx context.Context, session VideoSession, w io.Writer) error

func (*Client) GetAccountStatus

func (c *Client) GetAccountStatus() (*AccountStatus, error)

func (*Client) GetAvailableSessions

func (c *Client) GetAvailableSessions() ([]string, error)

func (*Client) GetChannelVideos

func (c *Client) GetChannelVideos(channelID string, page int) (*VideoListPage, error)

func (*Client) GetComments

func (c *Client) GetComments(server, threadKey string, params map[string]any) ([]*CommentThread, error)

func (*Client) GetMyList

func (c *Client) GetMyList(mylistId string) (*MyList, error)

func (*Client) GetMyListItems

func (c *Client) GetMyListItems(mylistId string) ([]*MyListItem, error)

func (*Client) GetMyLists

func (c *Client) GetMyLists() ([]*MyList, error)

func (*Client) GetPublicMyList

func (c *Client) GetPublicMyList(mylistId string) (*MyList, error)

func (*Client) GetPublicMyListRSS

func (c *Client) GetPublicMyListRSS(mylistId string) (*MyList, []*VideoInfo, error)

func (*Client) GetSeriesVideos

func (c *Client) GetSeriesVideos(seriesID string) (*SearchResult, error)

func (*Client) GetUserMyLists

func (c *Client) GetUserMyLists(userID int) ([]*MyList, error)

func (*Client) GetVideoData

func (c *Client) GetVideoData(contentId string) (*VideoData, error)

func (*Client) GetVideoRanking

func (c *Client) GetVideoRanking(genre RankingGenre, term RankingTerm, page int) (*VideoListPage, error)

func (*Client) LoadLoginSession

func (c *Client) LoadLoginSession(path string) error

func (*Client) Login

func (c *Client) Login(id, password string) error

func (*Client) LoginWithJsonFile

func (c *Client) LoginWithJsonFile(path string) error

func (*Client) Logout

func (c *Client) Logout() error

func (*Client) SaveLoginSession

func (c *Client) SaveLoginSession(path string) error

func (*Client) SearchByKeyword

func (c *Client) SearchByKeyword(s string, offset, limit int) (*SearchResult, error)

func (*Client) SearchByTag

func (c *Client) SearchByTag(tag string, offset, limit int) (*SearchResult, error)

func (*Client) SearchChannel

func (c *Client) SearchChannel(q string, mode SearchChannelMode, page int) ([]*ChannelInfo, error)

func (*Client) SearchVideo

func (c *Client) SearchVideo(q string, targets, fields []SearchField, sort string, offset, limit int, filter SearchFilter) (*SearchResult, error)

func (*Client) SearchVideo2

func (c *Client) SearchVideo2(req *SearchRequest) (*SearchResult, error)

func (*Client) SetSessionString

func (c *Client) SetSessionString(sessionStr string) error

type Comment

type Comment struct {
	ID          string   `json:"id"`
	No          int      `json:"no"`
	VposMs      int      `json:"vposMs"`
	Body        string   `json:"body"`
	Commands    []string `json:"commands"`
	UserID      string   `json:"userId"`
	IsPremium   bool     `json:"isPremium"`
	Score       int      `json:"score"`
	PostedAt    string   `json:"postedAt"`
	NicoruCount int      `json:"nicoruCount"`
	NicoruId    any      `json:"nicoruId"`
	Source      string   `json:"source"`
	IsMyPost    bool     `json:"isMyPost"`
}

type CommentThread

type CommentThread struct {
	ID           string     `json:"id"`
	Fork         string     `json:"fork"`
	CommentCount int        `json:"commentCount"`
	Comments     []*Comment `json:"comments"`
}

type DMCSession

type DMCSession struct {
	ID         string `json:"id"`
	ContentURI string `json:"content_uri"`
	Protocol   struct {
		Name       string                 `json:"name"`
		Parameters map[string]interface{} `json:"parameters"`
	} `json:"protocol"`
	KeepMethod struct {
		Heartbeat *struct {
			LifetimeMs   int    `json:"lifetime"`
			OnetimeToken string `json:"onetime_token"`
		} `json:"heartbeat"`
	} `json:"keep_method"`
	// contains filtered or unexported fields
}

func CreateDMCSession

func CreateDMCSession(client *http.Client, reqsession jsonObject, sessionApiURL string) (*DMCSession, error)

func CreateDMCSessionByVideoData

func CreateDMCSessionByVideoData(client *http.Client, data *VideoData) (*DMCSession, error)

func (*DMCSession) Download

func (session *DMCSession) Download(ctx context.Context, client *http.Client, w io.Writer, optionalStreamID string) error

func (*DMCSession) FileExtension

func (s *DMCSession) FileExtension() string

func (*DMCSession) IsHLS

func (s *DMCSession) IsHLS() bool

IsHLS returns true if protocol is hls

func (*DMCSession) IsHTTP

func (s *DMCSession) IsHTTP() bool

IsHTTP returns true if protocol is http or https

func (*DMCSession) IsRTMP

func (s *DMCSession) IsRTMP() bool

IsRTMP returns true if protocol is rtmp

type DomandAccessData

type DomandAccessData struct {
	ContentUrl string `json:"contentUrl"`
	CreateTime string `json:"createTime"`
	ExpireTime string `json:"expireTime"`
}

type DomandSession

type DomandSession struct {
	Data  DomandAccessData
	Video *SourceStream3
	Audio *SourceStream3
}

func CreateDomandSessionByVideoData

func CreateDomandSessionByVideoData(client *http.Client, data *VideoData) (*DomandSession, error)

func (*DomandSession) Download

func (s *DomandSession) Download(ctx context.Context, client *http.Client, w io.Writer, optionalStreamID string) error

func (*DomandSession) FileExtension

func (s *DomandSession) FileExtension() string

func (*DomandSession) SubStreams

func (s *DomandSession) SubStreams() [][]string

type HLSDownloader

type HLSDownloader struct {
	HttpClient    *http.Client
	TargetGroupID string
	// contains filtered or unexported fields
}

func NewHLSDownloader

func NewHLSDownloader(client *http.Client) *HLSDownloader

func (*HLSDownloader) Download

func (c *HLSDownloader) Download(ctx context.Context, url string, w io.Writer) error

func (*HLSDownloader) GetSegment

func (c *HLSDownloader) GetSegment(ctx context.Context, url string, w io.Writer) error

func (*HLSDownloader) GetSegment2

func (c *HLSDownloader) GetSegment2(ctx context.Context, url string, w io.Writer, key, iv []byte) error

type HTTPDownloader

type HTTPDownloader struct {
	HttpClient *http.Client
}

func NewHTTPDownloader

func NewHTTPDownloader(client *http.Client) *HTTPDownloader

func (*HTTPDownloader) Download

func (c *HTTPDownloader) Download(ctx context.Context, url string, w io.Writer) error

type MyList

type MyList struct {
	ID          int    `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	UserID      int64  `json:"user_id,string"`

	IsPublic    bool          `json:"isPublic"`
	CreatedAt   string        `json:"createdAt"`
	SampleItems []*MyListItem `json:"sampleItems"`
	Items       []*MyListItem `json:"items"`

	DefaultSortKey   string `json:"defaultSortKey"`
	DefaultSortOrder string `json:"defaultSortOrder"`
}

type MyListItem

type MyListItem struct {
	ItemID  int       `json:"itemId"`
	WatchID string    `json:"watchId"`
	Status  string    `json:"status"` // deleted, public
	AddedAt string    `json:"addedAt"`
	Video   VideoInfo `json:"video"`

	Description              string `json:"description"`
	DecoratedDescriptionHtml string `json:"decoratedDescriptionHtml"`
}

func (*MyListItem) IsDeleted

func (m *MyListItem) IsDeleted() bool

type MyListItemType

type MyListItemType int
const (
	MyListItemTypeVideo MyListItemType = 0
	MyListItemTypeSeiga MyListItemType = 5
	MyListItemTypeBook  MyListItemType = 6
)

func (*MyListItemType) UnmarshalJSON

func (m *MyListItemType) UnmarshalJSON(b []byte) error

type NicoSession

type NicoSession struct {
	NiconicoID    string `json:"niconicoId"`
	IsPremium     bool   `json:"premium"`
	SessionString string `json:"user_session"`
}

type OwnerInfo

type OwnerInfo map[string]any

type OwnerInfo_

type OwnerInfo_ struct {
	Type       string `json:"type"`
	ID         int    `json:"id,string"`
	Name       string `json:"name"`
	Visibility string `json:"visibility"`
	IconUrl    string `json:"iconUrl"`
}

type RankingGenre

type RankingGenre = string

type RankingTerm

type RankingTerm = string

type SearchChannelMode

type SearchChannelMode string
const (
	SearchChannelModeKeyword SearchChannelMode = "s"
	SearchChannelModeTag     SearchChannelMode = "t"
)

type SearchField

type SearchField = string
const (
	SearchFieldContentID      SearchField = "contentId"
	SearchFieldTitle          SearchField = "title"
	SearchFieldLengthSeconds  SearchField = "lengthSeconds"
	SearchFieldThumbnailURL   SearchField = "thumbnailUrl"
	SearchFieldViewCounter    SearchField = "viewCounter"
	SearchFieldMylistCounter  SearchField = "mylistCounter"
	SearchFieldCommentCounter SearchField = "commentCounter"
	SearchFieldDescription    SearchField = "description"
	SearchFieldTags           SearchField = "tags"
	SearchFieldTagsExact      SearchField = "tagsExact"
	SearchFieldLockTagsExact  SearchField = "lockTagsExact"
	SearchFieldCategoryTags   SearchField = "categoryTags"
	SearchFieldGenre          SearchField = "genre"
	SearchFieldGenreKey       SearchField = "genre.keyword"
	SearchFieldStartTime      SearchField = "startTime"
	SearchFieldUserID         SearchField = "userId"
	SearchFieldChannelID      SearchField = "channelId"
	SearchFieldThreadID       SearchField = "threadId"
)

type SearchFilter

type SearchFilter interface{}

TODO

func AndFilter

func AndFilter(filters []SearchFilter) SearchFilter

func EqualFilter

func EqualFilter(field SearchField, value string) SearchFilter

func NotFilter

func NotFilter(filter SearchFilter) SearchFilter

func OrFilter

func OrFilter(filters []SearchFilter) SearchFilter

func RangeFilter

func RangeFilter(field SearchField, from, to string, includeUpper bool) SearchFilter

type SearchRequest

type SearchRequest struct {
	Query   string
	Offset  int
	Limit   int
	Sort    string
	Targets []SearchField
	Filter  SearchFilter
	Fields  []SearchField
}

type SearchResult

type SearchResult struct {
	TotalCount int
	Offset     int
	Items      []*SearchResultItem
}

type SearchResultItem

type SearchResultItem struct {
	ContentID    string `json:"contentId"`
	Title        string `json:"title"`
	ThumbnailURL string `json:"thumbnailUrl"`
	Duration     int    `json:"lengthSeconds"`
	ViewCount    int    `json:"viewCounter"`
	MylistCount  int    `json:"mylistCounter"`
	CommentCount int    `json:"commentCounter"`

	Description string `json:"description"`
	UserID      int    `json:"userId"`
	ChannelID   int    `json:"channelId"`
	ThreadID    int    `json:"threadId"`
	Tags        string `json:"tags"`
	StartTime   string `json:"startTime"`
}

type SeriesItem

type SeriesItem struct {
	Meta  map[string]any `json:"meta"`
	Video *struct {
		Type         string `json:"type"`
		ID           string `json:"id"`
		Title        string `json:"title"`
		RegisteredAt string `json:"registeredAt"`
		Count        struct {
			View    int `json:"view"`
			Mylist  int `json:"mylist"`
			Comment int `json:"comment"`
		} `json:"count"`
		Thumbnail struct {
			Url string `json:"url"`
		} `json:"thumbnail"`
		Duration         int    `json:"duration"`
		ShortDescription string `json:"shortDescription"`
		Owner            struct {
			Type string `json:"type"`
			ID   string `json:"id"`
			Name string `json:"name"`
		} `json:"owner"`
	}
}

type SeriesResponse

type SeriesResponse struct {
	Meta map[string]any `json:"meta"`
	Data struct {
		TotalCount int          `json:"totalCount"`
		Items      []SeriesItem `json:"items"`
	} `json:"data"`
}

type SmileSession

type SmileSession struct {
	VideoData *VideoData
}

func CreateSmileSessionByVideoData

func CreateSmileSessionByVideoData(client *http.Client, data *VideoData) (*SmileSession, error)

func (*SmileSession) Download

func (s *SmileSession) Download(ctx context.Context, client *http.Client, w io.Writer, optionalStreamID string) error

func (*SmileSession) FileExtension

func (s *SmileSession) FileExtension() string

type SourceStream

type SourceStream struct {
	ID           string `json:"id"`
	Available    bool   `json:"available"`
	Bitrate      int    `json:"bitrate"`
	SamplingRate int    `json:"sampling_rate"`
	Resolution   struct {
		Width  int `json:"width"`
		Height int `json:"height"`
	} `json:"resolution"`
}

type SourceStream2

type SourceStream2 struct {
	ID        string `json:"id"`
	Available bool   `json:"isAvailable"`
	Metadata  struct {
		SamplingRate int `json:"samplingRate"`
		Bitrate      int `json:"bitrate"`
		Resolution   struct {
			Width  int `json:"width"`
			Height int `json:"height"`
		} `json:"resolution"`
	} `json:"metadata"`
}

func (*SourceStream2) SourceStream

func (s *SourceStream2) SourceStream() *SourceStream

type SourceStream3

type SourceStream3 struct {
	ID           string `json:"id"`
	Available    bool   `json:"isAvailable"`
	Label        any    `json:"label"`
	Bitrate      int    `json:"bitRate"`
	QualityLevel int    `json:"qualityLevel"`

	// Video
	Width                               int `json:"width"`
	Height                              int `json:"height"`
	RecommendedHighestAudioQualityLevel int `json:"recommendedHighestAudioQualityLevel"`

	// Audio
	SamplingRate       int   `json:"samplingRate"`
	LoudnessCollection []any `json:"loudnessCollection"`
}

type VideoData

type VideoData struct {
	Video struct {
		BaseVideoInfo

		// Deprecated?
		DMC struct {
			Quality struct {
				Audios []*SourceStream `json:"audios"`
				Videos []*SourceStream `json:"videos"`
			} `json:"quality"`
			SessionAPI map[string]interface{} `json:"session_api"`
			TrackingID string                 `json:"tracking_id"`
			Encryption map[string]interface{} `json:"encryption"`
		} `json:"dmcInfo"`
		// Deprecated?
		Smile struct {
			URL              string   `json:"url"`
			CurrentQualityID string   `json:"currentQualityId"`
			QualityIds       []string `json:"qualityIds"`
			IsSlowLine       bool     `json:"isSlowLine"`
		} `json:"smileInfo"`
	} `json:"video"`
	// temp1.media.delivery.movie.audios
	Media struct {
		Delivery struct {
			Movie struct {
				Audios  []*SourceStream2       `json:"audios"`
				Videos  []*SourceStream2       `json:"videos"`
				Session map[string]interface{} `json:"session"`
			} `json:"movie"`
			Encryption map[string]interface{} `json:"encryption"`
			TrackingID string                 `json:"trackingId"`
		} `json:"delivery"`
		DeliveryLegacy struct {
		} `json:"deliveryLegacy"`

		// v2024
		Domand *struct {
			Audios []*SourceStream3 `json:"audios"`
			Videos []*SourceStream3 `json:"videos"`

			IsStoryboardAvailable bool   `json:"isStoryboardAvailable"`
			AccessRightKey        string `json:"accessRightKey"`
		} `json:"domand"`
	} `json:"media"`
	Thread  map[string]interface{} `json:"thread"`
	Owner   OwnerInfo              `json:"owner"`
	Channel map[string]interface{} `json:"channel"`
	Context map[string]interface{} `json:"context"`

	Comment struct {
		NvComment *struct {
			Params    map[string]any `json:"params"`
			Server    string         `json:"server"`
			Threadkey string         `json:"threadKey"`
		} `json:"nvComment"`
		Threads []map[string]any `json:"threads"`
	} `json:"comment"`

	Tag struct {
		Items []struct {
			Name   string `json:"name"`
			Locked bool   `json:"isLocked"`
		} `json:"items"`
	} `json:"tag"`

	// v2024
	Client struct {
		NicoSID      string `json:"nicosid"`
		WatchId      string `json:"watchId"`
		WatchTrackId string `json:"watchTrackId"`
	} `json:"client"`
	Payment struct {
		IsPPV bool `json:"isPpv"`
	} `json:"payment"`
}

JSON.parse($("#js-initial-watch-data").dataset.apiData);

func (*VideoData) GenDMCSessionReq

func (data *VideoData) GenDMCSessionReq(audio, video string) (jsonObject, error)

func (*VideoData) GetAvailableAudio

func (v *VideoData) GetAvailableAudio() *SourceStream

func (*VideoData) GetAvailableSource

func (v *VideoData) GetAvailableSource(sources []*SourceStream) *SourceStream

func (*VideoData) GetAvailableSource3

func (v *VideoData) GetAvailableSource3(sources []*SourceStream3) *SourceStream3

func (*VideoData) GetAvailableVideo

func (v *VideoData) GetAvailableVideo() *SourceStream

func (*VideoData) GetEncryption

func (v *VideoData) GetEncryption() map[string]interface{}

func (*VideoData) GetPreferredAudio

func (v *VideoData) GetPreferredAudio() *SourceStream3

func (*VideoData) GetPreferredVideo

func (v *VideoData) GetPreferredVideo() *SourceStream3

func (*VideoData) GetSessionData

func (v *VideoData) GetSessionData() map[string]interface{}

func (*VideoData) IsDMC

func (v *VideoData) IsDMC() bool

func (*VideoData) IsDomand

func (v *VideoData) IsDomand() bool

func (*VideoData) IsNeedPayment

func (v *VideoData) IsNeedPayment() bool

func (*VideoData) IsSmile

func (v *VideoData) IsSmile() bool

func (*VideoData) SmileFileExtension

func (v *VideoData) SmileFileExtension() string

type VideoInfo

type VideoInfo struct {
	BaseVideoInfo

	Owner OwnerInfo `json:"owner"`

	// mylist
	Type                 string   `json:"type"`
	ShortDescription     string   `json:"shortDescription"`
	IsChannelVideo       bool     `json:"isChannelVideo"`
	IsPaymentRequired    bool     `json:"isPaymentRequired"`
	LatestCommentSummary string   `json:"latestCommentSummary"`
	PlaybackPosition     *float32 `json:"playbackPosition"`
}

type VideoListPage

type VideoListPage struct {
	Title string
	Owner string
	Items []*VideoInfo
}

type VideoResponse

type VideoResponse struct {
	Meta struct {
		Status int    `json:"status"`
		Code   string `json:"code"`
	} `json:"meta"`
	Data struct {
		Res *VideoData `json:"response"`
	} `json:"data"`
}

JSON.parse($("[name=server-response]").content);

type VideoSession

type VideoSession interface {
	FileExtension() string
	Download(ctx context.Context, client *http.Client, w io.Writer, optionalStreamID string) error
}

Directories

Path Synopsis
cmd
nigo command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL