From eee4e305858ba105c9dffaba55cf6bc6b1a98dc7 Mon Sep 17 00:00:00 2001 From: eson Date: Tue, 18 Aug 2020 16:50:49 +0800 Subject: [PATCH 01/18] fix: twistcasting tags error. change: twistcasting, some filed type to number --- .../twitcasting_extractor.go | 95 +++++++++++-------- .../twitcasting_extractor_test.go | 2 +- go.mod | 2 +- go.sum | 10 +- 4 files changed, 60 insertions(+), 49 deletions(-) diff --git a/extractor/twitcasting_extractor/twitcasting_extractor.go b/extractor/twitcasting_extractor/twitcasting_extractor.go index 9f0b031..13f419e 100644 --- a/extractor/twitcasting_extractor/twitcasting_extractor.go +++ b/extractor/twitcasting_extractor/twitcasting_extractor.go @@ -2,9 +2,10 @@ package main import ( "database/sql" + "encoding/json" "intimate" "log" - "regexp" + "os" "strconv" "strings" "time" @@ -21,8 +22,8 @@ var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() type LiveData struct { UserName string `exp:"//span[@class='tw-live-author__info-username']" method:"Text"` - Follower string `exp:"(//span[@class='tw-user-nav-list-count'])[2]" method:"Text"` - MaxViews string `exp:"//span[@id='max_viewer_count']" method:"Text"` + Follower int64 `exp:"(//span[@class='tw-user-nav-list-count'])[2]" method:"r:ExtractNumber"` + MaxViews int64 `exp:"//span[@id='max_viewer_count']/text()" method:"r:ExtractNumber"` LiveTitle string `exp:"//meta[@property='og:title']" method:"AttributeValue,content"` LiveStart string `exp:"//time[@data-kind='relative']" method:"AttributeValue,datetime"` LiveDuration string `exp:"//span[@id='updatetimer']" method:"AttributeValue,data-duration"` @@ -49,9 +50,11 @@ func main() { continue } var ldata *LiveData + f, _ := os.OpenFile("./twistcasting.html", os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) + f.Write(resp.Content()) etor := extractor.ExtractHtml(resp.Content()) ldata = etor.GetObjectByTag(LiveData{}).(*LiveData) - ldata.MaxViews = regexp.MustCompile("\\d+").FindString(ldata.MaxViews) + // ldata.MaxViews = regexp.MustCompile("\\d+").FindString(ldata.MaxViews) coincount := 0 for i := 0; ; i++ { @@ -90,10 +93,17 @@ func main() { } } + var tags []byte + tags, err = json.Marshal(ldata.Tags) + if err != nil { + log.Println(err, streamer.UserId) + } + streamer.Platform = intimate.Ptwitcasting streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} streamer.UserName = sql.NullString{String: ldata.UserName, Valid: true} streamer.Operator = 0 + streamer.Tags = tags // streamer.UpdateInterval = 60 clog := &intimate.CollectLog{} clog.UserId = streamer.UserId @@ -101,52 +111,59 @@ func main() { clog.Platform = streamer.Platform clog.UpdateTime = streamer.UpdateTime clog.LiveTitle = sql.NullString{String: ldata.LiveTitle, Valid: true} - fl, err := intimate.ParseNumberEx(ldata.Follower) - if err == nil { - clog.Followers = sql.NullInt64{Int64: int64(fl), Valid: true} - switch { - case fl <= 100: - streamer.UpdateInterval = 360 - case fl <= 1000: - streamer.UpdateInterval = 240 - case fl <= 100: - streamer.UpdateInterval = 120 - default: - streamer.UpdateInterval = 60 - } - } else { - log.Println(err) - } + clog.Tags = tags - views, err := strconv.Atoi(ldata.MaxViews) - if err == nil { - clog.Views = sql.NullInt64{Int64: int64(views), Valid: true} - } else { - clog.Views = sql.NullInt64{Int64: int64(0), Valid: true} - // log.Println(err, streamer.UserId) + // fl, err := intimate.ParseNumberEx(ldata.Follower) + // if err == nil { + clog.Followers = sql.NullInt64{Int64: int64(ldata.Follower), Valid: true} + switch { + case ldata.Follower <= 100: + streamer.UpdateInterval = 360 + case ldata.Follower <= 1000: + streamer.UpdateInterval = 240 + case ldata.Follower <= 100: + streamer.UpdateInterval = 120 + default: + streamer.UpdateInterval = 60 } + streamer.UpdateInterval = 60 + // } else { + // log.Println(err) + // } + + clog.Views = sql.NullInt64{Int64: ldata.MaxViews, Valid: true} + // views, err := strconv.Atoi(ldata.MaxViews) + // if err == nil { + // clog.Views = sql.NullInt64{Int64: int64(views), Valid: true} + // } else { + // clog.Views = sql.NullInt64{Int64: int64(0), Valid: true} + // // log.Println(err, streamer.UserId) + // } // st, err := strconv.Atoi(ldata.LiveStart) - st, err := time.Parse("Mon, 02 Jan 2006 15:04:05 -0700", ldata.LiveStart) - if err == nil { - startTime := st - clog.LiveStartTime = sql.NullTime{Time: startTime, Valid: true} - dt, err := strconv.Atoi(ldata.LiveDuration) - if time.Now().Sub(startTime) >= time.Hour*24*90 { - streamer.Operator = 5 - } - + if ldata.LiveStart != "" { + st, err := time.Parse("Mon, 02 Jan 2006 15:04:05 -0700", ldata.LiveStart) if err == nil { - endTime := startTime.Add((time.Duration)(dt) * time.Millisecond) - clog.LiveEndTime = sql.NullTime{Time: endTime, Valid: true} + startTime := st + clog.LiveStartTime = sql.NullTime{Time: startTime, Valid: true} + dt, err := strconv.Atoi(ldata.LiveDuration) + if time.Now().Sub(startTime) >= time.Hour*24*90 { + streamer.Operator = 5 + } + + if err == nil { + endTime := startTime.Add((time.Duration)(dt) * time.Millisecond) + clog.LiveEndTime = sql.NullTime{Time: endTime, Valid: true} + } else { + log.Println(err, streamer.UserId) + } } else { log.Println(err, streamer.UserId) } - } else { - log.Println(err, streamer.UserId) } streamer.LatestLogUid = estore.InsertClog(clog) estore.UpdateStreamer(streamer) + log.Println(streamer.UserId) } } diff --git a/extractor/twitcasting_extractor/twitcasting_extractor_test.go b/extractor/twitcasting_extractor/twitcasting_extractor_test.go index 3ed48ff..811b2d3 100644 --- a/extractor/twitcasting_extractor/twitcasting_extractor_test.go +++ b/extractor/twitcasting_extractor/twitcasting_extractor_test.go @@ -10,7 +10,7 @@ import ( // Follower string `exp:".//span[@class='tw-user-nav-list-count']" method:"Text"` // } -func estMain(t *testing.T) { +func TestMain(t *testing.T) { main() } diff --git a/go.mod b/go.mod index 312edd1..7794c12 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module intimate go 1.15 require ( - github.com/474420502/extractor v0.9.5 + github.com/474420502/extractor v0.9.6 github.com/474420502/focus v0.12.0 github.com/474420502/gcurl v0.2.0 github.com/474420502/requests v1.7.0 diff --git a/go.sum b/go.sum index 65f21fa..0ac5376 100644 --- a/go.sum +++ b/go.sum @@ -2,18 +2,14 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= -github.com/474420502/extractor v0.9.5 h1:nM3/1tNL8BHS3PN9eXvm8Ve3hqTReKNB+ba8VpdL8bw= -github.com/474420502/extractor v0.9.5/go.mod h1:vJnXWmvO5bJDW4Yag0GoE2GxtHRg03TAxp2oXN1DcSY= +github.com/474420502/extractor v0.9.6 h1:mwwzwVeu/sZ4FV190Bl32ta4iVjERBWL6eGLXRDlAtg= +github.com/474420502/extractor v0.9.6/go.mod h1:vJnXWmvO5bJDW4Yag0GoE2GxtHRg03TAxp2oXN1DcSY= github.com/474420502/focus v0.12.0 h1:+icbmj7IEOefvTegHt5EpcHt6WFbe2miIrceUJx2Evo= github.com/474420502/focus v0.12.0/go.mod h1:d0PMjtMxFz1a9HIhwyFPkWa+JF+0LgOrEUfd8iZka6s= -github.com/474420502/gcurl v0.1.2 h1:ON9Yz3IgAdtDlFlHfkAJ3aIEBDxH0RiViPE5ST5ohKg= -github.com/474420502/gcurl v0.1.2/go.mod h1:hws5q/Ao64bXLLDnldz9VyTQUndTWc/i5DzdEazFfoM= github.com/474420502/gcurl v0.2.0 h1:m6+vw4NX4f5Tfp7c3nuaIgHUE/7zTX6K3xK+pTCBoCo= github.com/474420502/gcurl v0.2.0/go.mod h1:kJZDbgXn5wbAaR+hhBi4Sbw44P4igJ7qYXC6mejLuhQ= github.com/474420502/htmlquery v1.2.4-0.20200812072201-e871dd09247a h1:E1T6CYQKsUn7fMvNbeKfISjBLfOJjZX4KpWwStT20Kc= github.com/474420502/htmlquery v1.2.4-0.20200812072201-e871dd09247a/go.mod h1:AoSN890esHwNKecV0tCs+W0ele1xgFL1Jqk6UcrdxgU= -github.com/474420502/requests v1.6.0 h1:f4h4j40eT0P5whhg9LdkotD8CaKjtuDu/vz9iSUkCgY= -github.com/474420502/requests v1.6.0/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= github.com/474420502/requests v1.7.0 h1:oaBwVrxZ7yZ+hDOKwHm2NflYib2y1geIUxBxQ2U48mw= github.com/474420502/requests v1.7.0/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -24,8 +20,6 @@ github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e h1:4ZrkT/RzpnRO github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k= github.com/Pallinder/go-randomdata v1.1.0 h1:gUubB1IEUliFmzjqjhf+bgkg1o6uoFIkRsP3VrhEcx8= github.com/Pallinder/go-randomdata v1.1.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= -github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg= -github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0= github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= From 5d501198253c134cf1025ad291d2eddf1091c208 Mon Sep 17 00:00:00 2001 From: eson Date: Fri, 28 Aug 2020 19:07:12 +0800 Subject: [PATCH 02/18] add new nimo code change more --- .../openrec_extractor/openrec_extractor.go | 7 +- .../twitcasting_extractor.go | 36 +- .../twitch_extractor/tiwtch_extractor.go | 28 +- go.mod | 7 +- go.sum | 20 + platform_list.go | 3 + store.go | 78 +- supervisor_conf/.gitignore | 1 + supervisor_conf/clear_log.sh | 7 + supervisor_conf/createln.sh | 9 +- supervisor_conf/openrec_extractor.conf | 6 +- supervisor_conf/openrec_task1.conf | 6 +- supervisor_conf/openrec_task2.conf | 6 +- supervisor_conf/test.conf | 12 - supervisor_conf/twitcasting_extractor.conf | 6 +- supervisor_conf/twitcasting_task1.conf | 6 +- supervisor_conf/twitch_extractor.conf | 6 +- supervisor_conf/twitch_extractor_p1.conf | 6 +- supervisor_conf/twitch_extractor_p2.conf | 6 +- supervisor_conf/twitch_task2.conf | 6 +- supervisor_conf/xvfb.conf | 7 +- table_list.go | 3 + tasks/nimo/nimo_task1/nimo_task1.go | 106 + tasks/nimo/nimo_task1/nimo_task1_test.go | 55 + tasks/openrec/openrec_task1/task_openrec.go | 2 +- tasks/openrec/openrec_task2/task_openrec.go | 2 +- tasks/twitch/twitch_task1/task_twitch_test.go | 2 +- tasks/twitch/twitch_task2/task_twitch.go | 4 +- tasks/twitch/twitch_task2/task_twitch_test.go | 2 +- testfile/nimo1.json | 10205 ++++++++++++++++ 30 files changed, 10540 insertions(+), 110 deletions(-) create mode 100644 supervisor_conf/.gitignore create mode 100644 supervisor_conf/clear_log.sh delete mode 100644 supervisor_conf/test.conf create mode 100644 tasks/nimo/nimo_task1/nimo_task1.go create mode 100644 tasks/nimo/nimo_task1/nimo_task1_test.go create mode 100644 testfile/nimo1.json diff --git a/extractor/openrec_extractor/openrec_extractor.go b/extractor/openrec_extractor/openrec_extractor.go index 4bd51df..b0c37d9 100644 --- a/extractor/openrec_extractor/openrec_extractor.go +++ b/extractor/openrec_extractor/openrec_extractor.go @@ -27,7 +27,7 @@ type UserLive struct { Title string `exp:"//h1[contains(@class,'MovieTitle__Title')]"` LiveStartTime string `exp:"//meta[@itemprop='uploadDate']/@content"` LiveEndTime string `exp:"//meta[@itemprop='duration']/@content"` - Tags []string `exp:"//a[contains(@class,'TagButton')]"` + Tags []string `exp:"//div[contains(@class,'MovieMetaContent__TagContainer')]//a[@role ='button']"` } // Execute 执行 @@ -135,8 +135,9 @@ func Execute() { streamer.Uid = source.StreamerId.Int64 streamer.UpdateTime = source.UpdateTime - streamer.Tags = clog.Tags - + if clog.Tags != nil { + streamer.Tags = clog.Tags + } clog.Platform = intimate.Popenrec clog.UserId = userId clog.UpdateTime = source.UpdateTime diff --git a/extractor/twitcasting_extractor/twitcasting_extractor.go b/extractor/twitcasting_extractor/twitcasting_extractor.go index 13f419e..c0b6a8e 100644 --- a/extractor/twitcasting_extractor/twitcasting_extractor.go +++ b/extractor/twitcasting_extractor/twitcasting_extractor.go @@ -113,42 +113,38 @@ func main() { clog.LiveTitle = sql.NullString{String: ldata.LiveTitle, Valid: true} clog.Tags = tags - // fl, err := intimate.ParseNumberEx(ldata.Follower) - // if err == nil { clog.Followers = sql.NullInt64{Int64: int64(ldata.Follower), Valid: true} switch { case ldata.Follower <= 100: - streamer.UpdateInterval = 360 + streamer.UpdateInterval = 720 case ldata.Follower <= 1000: + streamer.UpdateInterval = 320 + case ldata.Follower <= 10000: streamer.UpdateInterval = 240 - case ldata.Follower <= 100: - streamer.UpdateInterval = 120 default: - streamer.UpdateInterval = 60 + streamer.UpdateInterval = 120 } - streamer.UpdateInterval = 60 - // } else { - // log.Println(err) - // } clog.Views = sql.NullInt64{Int64: ldata.MaxViews, Valid: true} - // views, err := strconv.Atoi(ldata.MaxViews) - // if err == nil { - // clog.Views = sql.NullInt64{Int64: int64(views), Valid: true} - // } else { - // clog.Views = sql.NullInt64{Int64: int64(0), Valid: true} - // // log.Println(err, streamer.UserId) - // } - - // st, err := strconv.Atoi(ldata.LiveStart) if ldata.LiveStart != "" { st, err := time.Parse("Mon, 02 Jan 2006 15:04:05 -0700", ldata.LiveStart) if err == nil { startTime := st clog.LiveStartTime = sql.NullTime{Time: startTime, Valid: true} dt, err := strconv.Atoi(ldata.LiveDuration) - if time.Now().Sub(startTime) >= time.Hour*24*90 { + + liveduration := time.Now().Sub(startTime) + switch { + case liveduration >= time.Hour*24*240: streamer.Operator = 5 + case liveduration >= time.Hour*24*60: + streamer.UpdateInterval = 60 * 24 * 30 + case liveduration >= time.Hour*24*30: + streamer.UpdateInterval = 60 * 24 * 15 + case liveduration >= time.Hour*24*15: + streamer.UpdateInterval = 60 * 24 * 7 + case liveduration >= time.Hour*24*7: + streamer.UpdateInterval = 60 * 24 * 3 } if err == nil { diff --git a/extractor/twitch_extractor/tiwtch_extractor.go b/extractor/twitch_extractor/tiwtch_extractor.go index 187ae3e..c6173ba 100644 --- a/extractor/twitch_extractor/tiwtch_extractor.go +++ b/extractor/twitch_extractor/tiwtch_extractor.go @@ -22,21 +22,14 @@ func main() { wd := intimate.GetChromeDriver(3030) ps := intimate.NewPerfectShutdown() - counter := intimate.NewCounter() - counter.SetMaxLimit(200) - counter.SetMaxToDo(func(olist ...interface{}) error { - owd := olist[0].(*selenium.WebDriver) - (*owd).Close() - (*owd).Quit() - *owd = intimate.GetChromeDriver(3030) - return nil - }, &wd) + var count = 0 + var countlimt = 200 var lasterr error = nil // var err error for !ps.IsClose() { - streamer, err := estore.Pop(intimate.Ptwitch, 0) + streamer, err := estore.PopNoWait(intimate.Ptwitch, "tags is NULL", 15) if streamer == nil || err != nil { if err != lasterr { log.Println(err, lasterr) @@ -117,18 +110,23 @@ func main() { case fl > 100000: streamer.UpdateInterval = 120 case fl > 10000: - streamer.UpdateInterval = 240 + streamer.UpdateInterval = 240 * 2 case fl > 1000: - streamer.UpdateInterval = 360 + streamer.UpdateInterval = 360 * 2 case fl > 100: - streamer.UpdateInterval = 720 + streamer.UpdateInterval = 720 * 2 case fl > 0: - streamer.UpdateInterval = 1440 + streamer.UpdateInterval = 1440 * 4 } streamer.UpdateTime = clog.UpdateTime estore.UpdateStreamer(streamer) - counter.AddWithReset(1) + count++ + if count >= countlimt { + count = 0 + // wd.Quit() + wd = intimate.GetChromeDriver(3030) + } } wd.Close() diff --git a/go.mod b/go.mod index 7794c12..7848053 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,14 @@ go 1.15 require ( github.com/474420502/extractor v0.9.6 github.com/474420502/focus v0.12.0 - github.com/474420502/gcurl v0.2.0 - github.com/474420502/requests v1.7.0 + github.com/474420502/gcurl v0.4.4 + github.com/474420502/requests v1.9.1 + github.com/davecgh/go-spew v1.1.1 github.com/go-sql-driver/mysql v1.5.0 github.com/lestrrat-go/libxml2 v0.0.0-20200215080510-6483566f52cb github.com/tebeka/selenium v0.9.9 github.com/tidwall/gjson v1.6.0 github.com/tidwall/pretty v1.0.1 // indirect - golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect + golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect gopkg.in/yaml.v2 v2.3.0 ) diff --git a/go.sum b/go.sum index 0ac5376..c7770c9 100644 --- a/go.sum +++ b/go.sum @@ -8,10 +8,28 @@ github.com/474420502/focus v0.12.0 h1:+icbmj7IEOefvTegHt5EpcHt6WFbe2miIrceUJx2Ev github.com/474420502/focus v0.12.0/go.mod h1:d0PMjtMxFz1a9HIhwyFPkWa+JF+0LgOrEUfd8iZka6s= github.com/474420502/gcurl v0.2.0 h1:m6+vw4NX4f5Tfp7c3nuaIgHUE/7zTX6K3xK+pTCBoCo= github.com/474420502/gcurl v0.2.0/go.mod h1:kJZDbgXn5wbAaR+hhBi4Sbw44P4igJ7qYXC6mejLuhQ= +github.com/474420502/gcurl v0.3.0 h1:j0YP55ANQUHDF86pL5rCqfC+dX887uL9GxHFE3Zj31k= +github.com/474420502/gcurl v0.3.0/go.mod h1:kJZDbgXn5wbAaR+hhBi4Sbw44P4igJ7qYXC6mejLuhQ= +github.com/474420502/gcurl v0.4.0 h1:HOnuYhZD2rwvAXdrF1tqS6gQYYcpnpcPVdOVbDsFT4E= +github.com/474420502/gcurl v0.4.0/go.mod h1:kJZDbgXn5wbAaR+hhBi4Sbw44P4igJ7qYXC6mejLuhQ= +github.com/474420502/gcurl v0.4.1 h1:js/s+w1yBkpSU5vo3kXLQs5F+NMwbNWI23Bcx3LDnnQ= +github.com/474420502/gcurl v0.4.1/go.mod h1:IOyP4j8lUCJaHqODzRyeZQcrQy9DGDalLc3z1gVuiJ4= +github.com/474420502/gcurl v0.4.3 h1:CwyKPrv8mzSL+pa7mrYpuVNEC7rst6MdHx0Enn+7cUk= +github.com/474420502/gcurl v0.4.3/go.mod h1:IOyP4j8lUCJaHqODzRyeZQcrQy9DGDalLc3z1gVuiJ4= +github.com/474420502/gcurl v0.4.4 h1:ZILu7RRjDBGHpTGmuWGKf1NZZbZsC7AHPlI8RHqs9As= +github.com/474420502/gcurl v0.4.4/go.mod h1:7w4knyVJa1ia4I1xd0krG51fKLGwMmNn5sfG2zPWbqM= github.com/474420502/htmlquery v1.2.4-0.20200812072201-e871dd09247a h1:E1T6CYQKsUn7fMvNbeKfISjBLfOJjZX4KpWwStT20Kc= github.com/474420502/htmlquery v1.2.4-0.20200812072201-e871dd09247a/go.mod h1:AoSN890esHwNKecV0tCs+W0ele1xgFL1Jqk6UcrdxgU= github.com/474420502/requests v1.7.0 h1:oaBwVrxZ7yZ+hDOKwHm2NflYib2y1geIUxBxQ2U48mw= github.com/474420502/requests v1.7.0/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= +github.com/474420502/requests v1.8.1 h1:zR2PE97PY6qTfwCtUl7fJ2Sg7JEXcXZg2nxgxrOutFU= +github.com/474420502/requests v1.8.1/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= +github.com/474420502/requests v1.8.2 h1:DiNLp8IlHjZKgNJbzLcwt89YosWBfkmjEMNmUXxF+Hs= +github.com/474420502/requests v1.8.2/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= +github.com/474420502/requests v1.9.0 h1:c/oj1G4pGulIzljZ0WqoF8dkOCWjfJLmoyH+DCVRGH8= +github.com/474420502/requests v1.9.0/go.mod h1:x2T9l+e40R6kxxMvNm+YSZ9D6BHAXUDak4kQElIPJ9A= +github.com/474420502/requests v1.9.1 h1:gCDmBCW1ym8zOvKKBGjEG9wafMY7imYk2u28+Oy1WEc= +github.com/474420502/requests v1.9.1/go.mod h1:x2T9l+e40R6kxxMvNm+YSZ9D6BHAXUDak4kQElIPJ9A= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= @@ -112,6 +130,8 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/platform_list.go b/platform_list.go index 246e991..98ef433 100644 --- a/platform_list.go +++ b/platform_list.go @@ -12,4 +12,7 @@ const ( // Ptwitcasting twitcasting 平台 Ptwitcasting Platform = "twitcasting" + + // PNimo PNimo 平台 + PNimo Platform = "nimo" ) diff --git a/store.go b/store.go index 82918ad..d49df1e 100644 --- a/store.go +++ b/store.go @@ -228,15 +228,13 @@ func NewStoreExtractor() *StoreExtractor { return &StoreExtractor{db: db} } -// Pop 弹出一条未处理的数据 -func (store *StoreExtractor) Pop(platform Platform, operators ...int32) (*Streamer, error) { - +func (store *StoreExtractor) PopNoWait(platform Platform, condition string, operators ...int32) (*Streamer, error) { tx, err := store.db.Begin() if err != nil { return nil, err } var args = []interface{}{string(platform)} - selectSQL := `select uid, update_time, user_id, update_url, is_update_streamer, update_interval from ` + StreamerTable + ` where platform = ? and TIMESTAMPDIFF(MINUTE , update_time, CURRENT_TIMESTAMP()) >= update_interval` + selectSQL := `select uid, update_time, user_id, tags, live_url, update_url, is_update_streamer, update_interval from ` + StreamerTable + ` where platform = ? and ` + condition if len(operators) == 0 { selectSQL += " and operator = ?" args = append(args, 0) @@ -264,7 +262,52 @@ func (store *StoreExtractor) Pop(platform Platform, operators ...int32) (*Stream s := &Streamer{} // uid, url, target_type, source, ext, operator - err = row.Scan(&s.Uid, &s.UpdateTime, &s.UserId, &s.UpdateUrl, &s.IsUpdateStreamer, &s.UpdateInterval) + err = row.Scan(&s.Uid, &s.UpdateTime, &s.UserId, &s.Tags, &s.LiveUrl, &s.UpdateUrl, &s.IsUpdateStreamer, &s.UpdateInterval) + if err != nil { + return nil, err + } + s.Set("LastOperator", s.Operator) + _, err = tx.Exec("update "+StreamerTable+" set operator = ? where uid = ?", OperatorWait, s.Uid) + return s, nil +} + +// Pop 弹出一条未处理的数据 +func (store *StoreExtractor) Pop(platform Platform, operators ...int32) (*Streamer, error) { + + tx, err := store.db.Begin() + if err != nil { + return nil, err + } + var args = []interface{}{string(platform)} + selectSQL := `select uid, update_time, user_id, tags, live_url, update_url, is_update_streamer, update_interval from ` + StreamerTable + ` where platform = ? and TIMESTAMPDIFF(MINUTE , update_time, CURRENT_TIMESTAMP()) >= update_interval` + if len(operators) == 0 { + selectSQL += " and operator = ?" + args = append(args, 0) + } else { + for _, operator := range operators { + selectSQL += " and operator = ?" + args = append(args, operator) + } + } + + defer func() { + err := tx.Commit() + if err != nil { + log.Println(err) + err = tx.Rollback() + if err != nil { + log.Println(err) + } + } + store.popCount++ + }() + + // log.Println(selectSQL + ` limit 1 for update`) + row := tx.QueryRow(selectSQL+` limit 1 for update`, args...) + + s := &Streamer{} + // uid, url, target_type, source, ext, operator + err = row.Scan(&s.Uid, &s.UpdateTime, &s.UserId, &s.Tags, &s.LiveUrl, &s.UpdateUrl, &s.IsUpdateStreamer, &s.UpdateInterval) if err != nil { return nil, err } @@ -316,9 +359,9 @@ func (store *StoreExtractor) InsertStreamerList(streamerlist IGet) (isExists boo } // InsertStreamer Streamer表, 插入数据 -func (store *StoreExtractor) InsertStreamer(streamer IGet) (isExists bool) { +func (store *StoreExtractor) InsertStreamer(streamer *Streamer) (isExists bool) { // select uid from table where platform = ? and user_id = ? - selectSQL := "SELECT is_update_url, uid FROM " + StreamerTable + " WHERE platform = ? AND user_id = ?" + // selectSQL := "SELECT is_update_url, uid FROM " + StreamerTable + " WHERE platform = ? AND user_id = ?" tx, err := store.db.Begin() if err != nil { panic(err) @@ -335,18 +378,17 @@ func (store *StoreExtractor) InsertStreamer(streamer IGet) (isExists bool) { } }() - row := tx.QueryRow(selectSQL+` LIMIT 1 FOR UPDATE`, streamer.Get("Platform"), streamer.Get("UserId")) - var isUpdateUrl bool - var Uid int64 - if err = row.Scan(&isUpdateUrl, &Uid); err == nil { - if isUpdateUrl { - tx.Exec("UPDATE "+StreamerTable+" SET update_url = ?", streamer.Get("UpdateUrl")) - } - streamer.(ISet).Set("Uid", Uid) - return true - } + streamer.UpdateTime = sql.NullTime{Time: time.Now().Add(-time.Hour * 100000), Valid: true} + _, err = tx.Exec("INSERT IGNORE INTO "+StreamerTable+"(platform, user_id, user_name, live_url, update_url, tags, update_time) VALUES(?,?,?,?,?,?,?);", + streamer.Platform, + streamer.UserId, + streamer.UserName, + streamer.LiveUrl, + streamer.UpdateUrl, + streamer.Tags, + streamer.UpdateTime, + ) - _, err = tx.Exec("INSERT INTO "+StreamerTable+"(platform, user_id, update_url, tags, update_time) VALUES(?,?,?,?,?);", streamer.Get("Platform"), streamer.Get("UserId"), streamer.Get("UpdateUrl"), streamer.Get("Tags"), time.Now().Add(-time.Hour*100000)) if err != nil { panic(err) } diff --git a/supervisor_conf/.gitignore b/supervisor_conf/.gitignore new file mode 100644 index 0000000..2d29375 --- /dev/null +++ b/supervisor_conf/.gitignore @@ -0,0 +1 @@ +conf.d \ No newline at end of file diff --git a/supervisor_conf/clear_log.sh b/supervisor_conf/clear_log.sh new file mode 100644 index 0000000..1cce37f --- /dev/null +++ b/supervisor_conf/clear_log.sh @@ -0,0 +1,7 @@ +CURPATH=`pwd` +BINPATH=$(dirname "$CURPATH")/bin +find $BINPATH -type f -name 'log' -exec rm {} + + + + + diff --git a/supervisor_conf/createln.sh b/supervisor_conf/createln.sh index 1c092ed..7e5562e 100644 --- a/supervisor_conf/createln.sh +++ b/supervisor_conf/createln.sh @@ -1 +1,8 @@ -ln -sf `pwd`/*.conf /etc/supervisor/conf.d/ + +CURPATH=`pwd` +SUPPATH=$(dirname "$CURPATH") + +mkdir -p $CURPATH/conf.d +cp *.conf $CURPATH/conf.d/ +sed -i "s#MYPATH#$SUPPATH#g" $CURPATH/conf.d/*.conf +ln -sf $CURPATH/conf.d/*.conf /etc/supervisor/conf.d/ diff --git a/supervisor_conf/openrec_extractor.conf b/supervisor_conf/openrec_extractor.conf index 0b7f9de..da7c539 100644 --- a/supervisor_conf/openrec_extractor.conf +++ b/supervisor_conf/openrec_extractor.conf @@ -2,9 +2,9 @@ nodaemon=true [program:openrec_extractor] -directory = /home/eson/test/intimate/bin/openrec_extractor/ -command= /home/eson/test/intimate/bin/openrec_extractor/openrec_extractor +directory = MYPATH/bin/openrec_extractor/ +command= MYPATH/bin/openrec_extractor/openrec_extractor autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/openrec_extractor/log +stderr_logfile=MYPATH/bin/openrec_extractor/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/openrec_task1.conf b/supervisor_conf/openrec_task1.conf index b011692..15829c2 100644 --- a/supervisor_conf/openrec_task1.conf +++ b/supervisor_conf/openrec_task1.conf @@ -2,9 +2,9 @@ nodaemon=true [program:openrec_ranking] -directory = /home/eson/test/intimate/bin/openrec_task1 -command= /home/eson/test/intimate/bin/openrec_task1/openrec_task1 +directory = MYPATH/bin/openrec_task1 +command= MYPATH/bin/openrec_task1/openrec_task1 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/openrec_task1/log +stderr_logfile=MYPATH/bin/openrec_task1/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/openrec_task2.conf b/supervisor_conf/openrec_task2.conf index 99c65c3..1da544f 100644 --- a/supervisor_conf/openrec_task2.conf +++ b/supervisor_conf/openrec_task2.conf @@ -2,11 +2,11 @@ nodaemon=true [program:openrec_source] -directory = /home/eson/test/intimate/bin/openrec_task2/ -command= /home/eson/test/intimate/bin/openrec_task2/openrec_task2 +directory = MYPATH/bin/openrec_task2/ +command= MYPATH/bin/openrec_task2/openrec_task2 process_name=%(program_name)s_%(process_num)02d ;多进程名称 numprocs=4 ;启动多个进程 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/openrec_task2/log +stderr_logfile=MYPATH/bin/openrec_task2/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/test.conf b/supervisor_conf/test.conf deleted file mode 100644 index fb815c7..0000000 --- a/supervisor_conf/test.conf +++ /dev/null @@ -1,12 +0,0 @@ -# [supervisord] -# nodaemon=true - -# [program:openrec_extractor] -# directory = /home/eson/test/intimate/extractor/openrec_extractor -# command= /home/eson/test/intimate/extractor/openrec_extractor/openrec_extractor -# autorestart=true -# # stdout_logfile=/home/eson/test/intimate/extractor/openrec/stdout -# # stdout_logfile_maxbytes=0 -# stderr_logfile=/home/eson/test/intimate/extractor/openrec/log -# stderr_logfile_maxbytes=0 -# stopsignal=QUIT diff --git a/supervisor_conf/twitcasting_extractor.conf b/supervisor_conf/twitcasting_extractor.conf index 218b2b8..a4f55df 100644 --- a/supervisor_conf/twitcasting_extractor.conf +++ b/supervisor_conf/twitcasting_extractor.conf @@ -3,12 +3,12 @@ nodaemon=false [program:twitcasting_extractor] environment=DISPLAY=":99" -directory = /home/eson/test/intimate/bin/twitcasting_extractor/ -command= /home/eson/test/intimate/bin/twitcasting_extractor/twitcasting_extractor +directory = MYPATH/bin/twitcasting_extractor/ +command= MYPATH/bin/twitcasting_extractor/twitcasting_extractor process_name=%(program_name)s_%(process_num)02d ;多进程名称 numprocs=3 ;启动多个进程 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/twitcasting_extractor/log +stderr_logfile=MYPATH/bin/twitcasting_extractor/log # stderr_logfile=%(supervisorctl.var.directory)s/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/twitcasting_task1.conf b/supervisor_conf/twitcasting_task1.conf index 23dda7b..cf8cbe5 100644 --- a/supervisor_conf/twitcasting_task1.conf +++ b/supervisor_conf/twitcasting_task1.conf @@ -3,11 +3,11 @@ nodaemon=false [program:twitcasting_task1] environment=DISPLAY=":99" -directory = /home/eson/test/intimate/bin/twitcasting_task1/ -command= /home/eson/test/intimate/bin/twitcasting_task1/twitcasting_task1 +directory = MYPATH/bin/twitcasting_task1/ +command= MYPATH/bin/twitcasting_task1/twitcasting_task1 # process_name=%(program_name)s_%(process_num)02d ;多进程名称 # numprocs=1 ;启动多个进程 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/twitcasting_task1/log +stderr_logfile=MYPATH/bin/twitcasting_task1/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/twitch_extractor.conf b/supervisor_conf/twitch_extractor.conf index a8676a5..61b82ca 100644 --- a/supervisor_conf/twitch_extractor.conf +++ b/supervisor_conf/twitch_extractor.conf @@ -3,11 +3,11 @@ nodaemon=false [program:twitch_extractor] environment=DISPLAY=":99" -directory = /home/eson/test/intimate/bin/twitch_extractor -command= /home/eson/test/intimate/bin/twitch_extractor/twitch_extractor +directory = MYPATH/bin/twitch_extractor +command= MYPATH/bin/twitch_extractor/twitch_extractor process_name=%(program_name)s_%(process_num)02d ;多进程名称 numprocs=5 ;启动多个进程 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/twitch_extractor/log +stderr_logfile=MYPATH/bin/twitch_extractor/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/twitch_extractor_p1.conf b/supervisor_conf/twitch_extractor_p1.conf index 36ac3fc..aea427e 100644 --- a/supervisor_conf/twitch_extractor_p1.conf +++ b/supervisor_conf/twitch_extractor_p1.conf @@ -3,11 +3,11 @@ nodaemon=true [program:twitch_extractor_p1] environment=DISPLAY=":99",pac_proxy=http://localhost:1090/pac -directory = /home/eson/test/intimate/bin/twitch_extractor -command= /home/eson/test/intimate/bin/twitch_extractor/twitch_extractor +directory = MYPATH/bin/twitch_extractor +command= MYPATH/bin/twitch_extractor/twitch_extractor process_name=%(program_name)s_%(process_num)02d ;多进程名称 numprocs=2 ;启动多个进程 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/twitch_extractor/log +stderr_logfile=MYPATH/bin/twitch_extractor/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/twitch_extractor_p2.conf b/supervisor_conf/twitch_extractor_p2.conf index 095de77..4c47d15 100644 --- a/supervisor_conf/twitch_extractor_p2.conf +++ b/supervisor_conf/twitch_extractor_p2.conf @@ -3,11 +3,11 @@ nodaemon=false [program:twitch_extractor_p2] environment=DISPLAY=":99",pac_proxy=http://localhost:1090/pac1 -directory = /home/eson/test/intimate/bin/twitch_extractor -command= /home/eson/test/intimate/bin/twitch_extractor/twitch_extractor +directory = MYPATH/bin/twitch_extractor +command= MYPATH/bin/twitch_extractor/twitch_extractor process_name=%(program_name)s_%(process_num)02d ;多进程名称 numprocs=2 ;启动多个进程 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/twitch_extractor/log +stderr_logfile=MYPATH/bin/twitch_extractor/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/twitch_task2.conf b/supervisor_conf/twitch_task2.conf index 7768d0e..8a12047 100644 --- a/supervisor_conf/twitch_task2.conf +++ b/supervisor_conf/twitch_task2.conf @@ -3,11 +3,11 @@ nodaemon=false [program:twitch_task2] environment=DISPLAY=":99" -directory = /home/eson/test/intimate/bin/twitch_task2 -command= /home/eson/test/intimate/bin/twitch_task2/twitch_task2 +directory = MYPATH/bin/twitch_task2 +command= MYPATH/bin/twitch_task2/twitch_task2 process_name=%(program_name)s_%(process_num)02d ;多进程名称 numprocs=6 ;启动多个进程 autorestart=true -stderr_logfile=/home/eson/test/intimate/bin/twitch_task2/log +stderr_logfile=MYPATH/bin/twitch_task2/log stderr_logfile_maxbytes=0 stopsignal=QUIT diff --git a/supervisor_conf/xvfb.conf b/supervisor_conf/xvfb.conf index 1ee51d6..d8da99a 100644 --- a/supervisor_conf/xvfb.conf +++ b/supervisor_conf/xvfb.conf @@ -3,11 +3,6 @@ nodaemon=true [program:xvfb-99] -# directory = /home/eson/test/intimate/extractor/openrec_extractor command=/usr/bin/Xvfb :99 -screen 0 1280x720x24 -ac -nolisten tcp -dpi 96 +extension RANDR -nolisten tcp autorestart=true -# # stdout_logfile=/home/eson/test/intimate/extractor/openrec/stdout -# # stdout_logfile_maxbytes=0 -# stderr_logfile=/home/eson/test/intimate/extractor/openrec/log -# stderr_logfile_maxbytes=0 -# stopsignal=QUIT + diff --git a/table_list.go b/table_list.go index cb12c70..1dc9545 100644 --- a/table_list.go +++ b/table_list.go @@ -12,4 +12,7 @@ const ( // STTwitcasting STTwitcasting源table名称 STTwitcasting SourceTable = "source_twitcasting" + + // STNimo nimo源table名称 + STNimo SourceTable = "source_nimo" ) diff --git a/tasks/nimo/nimo_task1/nimo_task1.go b/tasks/nimo/nimo_task1/nimo_task1.go new file mode 100644 index 0000000..d423e90 --- /dev/null +++ b/tasks/nimo/nimo_task1/nimo_task1.go @@ -0,0 +1,106 @@ +package main + +import ( + "database/sql" + "encoding/json" + "intimate" + "log" + "time" + + "github.com/474420502/gcurl" + "github.com/tidwall/gjson" +) + +// estore 解析存储连接实例 +var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() + +// Execute 执行 +func Execute() { + + nimoapi := `curl 'https://api.nimo.tv/oversea/nimo/api/v2/liveRoom/liveRoomPage-1-100-/HK/1028/1000' \ + -H 'authority: api.nimo.tv' \ + -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36' \ + -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary3bCA1lzvhj4kBR4Q' \ + -H 'accept: */*' \ + -H 'origin: https://www.nimo.tv' \ + -H 'sec-fetch-site: same-site' \ + -H 'sec-fetch-mode: cors' \ + -H 'sec-fetch-dest: empty' \ + -H 'referer: https://www.nimo.tv/lives' \ + -H 'accept-language: zh-CN,zh;q=0.9' \ + --data-binary $'------WebKitFormBoundary3bCA1lzvhj4kBR4Q\r\nContent-Disposition: form-data; name="keyType"\r\n\r\n0\r\n------WebKitFormBoundary3bCA1lzvhj4kBR4Q\r\nContent-Disposition: form-data; name="body"\r\n\r\n{"deviceType":7,"requestSource":"WEB","iNetType":5}\r\n------WebKitFormBoundary3bCA1lzvhj4kBR4Q--\r\n' \ + --compressed` + + curl := gcurl.Parse(nimoapi) + ses := curl.CreateSession() + tp := curl.CreateTemporary(ses) + + param := tp.PathParam("liveRoomPage-(1)-") + ps := intimate.NewPerfectShutdown() + for !ps.IsClose() { + + resp, err := tp.Execute() + if err != nil { + log.Println(err) + time.Sleep(time.Second) + continue + } + + result := gjson.ParseBytes(resp.Content()) + roomlist := result.Get("data.result.liveRoomViewList") + + if !roomlist.IsArray() { + log.Println("json is error") + log.Println(string(resp.Content())) + break + } + + rooms := roomlist.Array() + log.Println(tp.GetURLRawPath(), "rooms:", len(rooms)) + if len(rooms) == 0 { + param.IntSet(1) + time.Sleep(time.Minute * 10) + continue + } + + for _, room := range rooms { + + streamer := &intimate.Streamer{} + streamer.Platform = intimate.PNimo + + if userid := room.Get("id").String(); userid != "" { + + streamer.UserId = userid + streamer.LiveUrl = sql.NullString{String: "https://www.nimo.tv/live/" + userid, Valid: true} + + channel := room.Get("roomTypeName").String() + streamer.Channel = sql.NullString{String: channel, Valid: channel != ""} + username := room.Get("anchorName").String() + streamer.UserName = sql.NullString{String: username, Valid: username != ""} + + if rtags := room.Get("anchorLabels"); rtags.IsArray() { + + var tags []string + for _, r := range rtags.Array() { + tag := r.Get("labelName").String() + tags = append(tags, tag) + } + + data, err := json.Marshal(tags) + if err != nil { + panic(err) + } + streamer.Tags = data + + } + + streamer.UpdateInterval = 120 + // spew.Println(streamer) + estore.InsertStreamer(streamer) + } else { + log.Println("userid is null.", room.String()) + } + } + param.IntAdd(1) + } +} diff --git a/tasks/nimo/nimo_task1/nimo_task1_test.go b/tasks/nimo/nimo_task1/nimo_task1_test.go new file mode 100644 index 0000000..ab739ec --- /dev/null +++ b/tasks/nimo/nimo_task1/nimo_task1_test.go @@ -0,0 +1,55 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "testing" + + "github.com/474420502/gcurl" +) + +func CrawlContent(args ...interface{}) []byte { + nimoapi := `curl 'https://api.nimo.tv/oversea/nimo/api/v2/liveRoom/liveRoomPage-%d-30-/HK/1028/1000' \ + -H 'authority: api.nimo.tv' \ + -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36' \ + -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary3bCA1lzvhj4kBR4Q' \ + -H 'accept: */*' \ + -H 'origin: https://www.nimo.tv' \ + -H 'sec-fetch-site: same-site' \ + -H 'sec-fetch-mode: cors' \ + -H 'sec-fetch-dest: empty' \ + -H 'referer: https://www.nimo.tv/lives' \ + -H 'accept-language: zh-CN,zh;q=0.9' \ + --data-binary $'------WebKitFormBoundary3bCA1lzvhj4kBR4Q\r\nContent-Disposition: form-data; name="keyType"\r\n\r\n0\r\n------WebKitFormBoundary3bCA1lzvhj4kBR4Q\r\nContent-Disposition: form-data; name="body"\r\n\r\n{"deviceType":7,"requestSource":"WEB","iNetType":5}\r\n------WebKitFormBoundary3bCA1lzvhj4kBR4Q--\r\n' \ + --compressed` + + curl := gcurl.Parse(fmt.Sprintf(nimoapi, 1)) + tp := curl.CreateTemporary(nil) + + resp, err := tp.Execute() + if err != nil { + panic(err) + } + return resp.Content() +} + +func openTestFile(...interface{}) []byte { + f, err := os.Open("../../../testfile/nimo1.json") + if err != nil { + panic(err) + } + data, err := ioutil.ReadAll(f) + if err != nil { + panic(err) + } + return data +} + +var Crawl func(...interface{}) []byte + +func Test(t *testing.T) { + + Execute() + +} diff --git a/tasks/openrec/openrec_task1/task_openrec.go b/tasks/openrec/openrec_task1/task_openrec.go index 7a8774a..40ee747 100644 --- a/tasks/openrec/openrec_task1/task_openrec.go +++ b/tasks/openrec/openrec_task1/task_openrec.go @@ -34,7 +34,7 @@ func Execute() { -H 'if-none-match: W/"25edb-aUYBdmLqZcr6DW4ZWKX9r2aqolg"' \ --compressed` - g := gcurl.ParseRawCURL(turl) + g := gcurl.Parse(turl) tp := g.Temporary() for !ps.IsClose() { diff --git a/tasks/openrec/openrec_task2/task_openrec.go b/tasks/openrec/openrec_task2/task_openrec.go index 091944f..c88fa6f 100644 --- a/tasks/openrec/openrec_task2/task_openrec.go +++ b/tasks/openrec/openrec_task2/task_openrec.go @@ -69,7 +69,7 @@ func Execute() { cookies := ses.GetCookies(tp.GetParsedURL()) scurl := updateUrl["supporters"] //获取打赏者的数据 - curl := gcurl.ParseRawCURL(scurl) + curl := gcurl.Parse(scurl) supportersSession := curl.CreateSession() temporary := curl.CreateTemporary(supportersSession) diff --git a/tasks/twitch/twitch_task1/task_twitch_test.go b/tasks/twitch/twitch_task1/task_twitch_test.go index 6ee9af6..31f721c 100644 --- a/tasks/twitch/twitch_task1/task_twitch_test.go +++ b/tasks/twitch/twitch_task1/task_twitch_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func estCase1(t *testing.T) { +func TestCase1(t *testing.T) { Execute() } diff --git a/tasks/twitch/twitch_task2/task_twitch.go b/tasks/twitch/twitch_task2/task_twitch.go index 922d1b1..86fcc8f 100644 --- a/tasks/twitch/twitch_task2/task_twitch.go +++ b/tasks/twitch/twitch_task2/task_twitch.go @@ -159,7 +159,9 @@ func Execute() { streamer.Operator = 0 if estore.InsertStreamer(streamer) { // log.Println("streamer update tags", streamer.Uid, tags) - estore.Update(streamer, "Tags", streamer.Tags) + if streamer.Tags != nil { + estore.Update(streamer, "Tags", streamer.Tags) + } } } log.Println("streamer find", len(articles)) diff --git a/tasks/twitch/twitch_task2/task_twitch_test.go b/tasks/twitch/twitch_task2/task_twitch_test.go index a5537f5..ef64976 100644 --- a/tasks/twitch/twitch_task2/task_twitch_test.go +++ b/tasks/twitch/twitch_task2/task_twitch_test.go @@ -2,6 +2,6 @@ package main import "testing" -func estMain(t *testing.T) { +func TestMain(t *testing.T) { main() } diff --git a/testfile/nimo1.json b/testfile/nimo1.json new file mode 100644 index 0000000..130646c --- /dev/null +++ b/testfile/nimo1.json @@ -0,0 +1,10205 @@ +{ + "code": 200, + "message": "Request succeeded", + "data": { + "result": { + "lCID": 1000, + "pageControlView": { + "pageCount": 56, + "pageStep": 4, + "pageIndex": 1, + "count": 1657, + "pageSize": 30 + }, + "liveRoomViewList": [ + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 90017, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 6173062192, + "sharpness": null, + "roomType": 30, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201907311564594528136_2399511787339_avatar.png", + "roomTypeName": "我要活下去", + "isLottery": 0, + "anchorId": 2399511787339, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1568966074000, + "anchorLabelType": 1, + "labelId": 11, + "labelNameLang": "", + "sort": 420, + "labelName": "技術流", + "type": 4 + }, + { + "timeStamp": 1568966074000, + "anchorLabelType": 1, + "labelId": 8, + "labelNameLang": "", + "sort": 420, + "labelName": "幽默", + "type": 4 + } + ], + "roomSort": 3, + "lcidText": "Português", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Cerol", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/17419A696E6EBFB38FD80C2C61ED96AD_500x280.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/91DDDDA719DC13AF83D396775B093C53_338x190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/C7BD8F6B83AC2F138F9D88B39A6388DE_136x76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399511787339rde01ffe519fb9b8a51f052cafc9eb4d0_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 2399511787339, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 6173062192, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": [], + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f710022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c608000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102870a0a08000106307375323339393531313738373333397264653031666665353139666239623861353166303532636166633965623464301a0900010a060257531630737532333939353131373837333339726465303166666535313966623962386135316630353263616663396562346430261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce019f00f19f01019f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375323339393531313738373333397264653031666665353139666239623861353166303532636166633965623464307c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c630000022eae0c374b7c8120f39006a103e8b103e8c103e8d600e60861707069643d38310b0b160a36313733303632313932260a36313733303632313932325f4620020b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "freefire" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1046, + "superscriptType": 0, + "anchorCountryCode": "BR", + "fps": null, + "anchorAnnouncement": "https://discord.gg/cerol \nDISCORD QUE USO PARA FAZER LIVES\nINSTAGRAM: @cerolzera", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201908011564691997580_2399511787339_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201908011564691997580_2399511787339_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201908011564691997523_2399511787339_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "00:00H CAMP", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "cerol", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 31425, + "onlineStatus": 0, + "endLiveTime": 1598428190, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 6954924882, + "sharpness": null, + "roomType": 30, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201904231555993088357_2439512362619_avatar.png", + "roomTypeName": "我要活下去", + "isLottery": 0, + "anchorId": 2439512362619, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1568968201000, + "anchorLabelType": 1, + "labelId": 11, + "labelNameLang": "", + "sort": 420, + "labelName": "技術流", + "type": 4 + } + ], + "roomSort": 3, + "lcidText": "Español ", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "MrStiven Tc", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/B7D0EF8D044F1D125F8317AA0C34D5E5_4d28a080513aa675e7de4965a0a8c922.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/B276AE0DE7166C2457235C56C8A9FFEB_cd5242a18fda4f96154cdd33251fde41.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/93B1B8BDF45A45F48D9C98D64B487B9F_7f324d7e7ff201cdc5d82edb06b2e21e.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_high.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439512362619rd9207ae57cab633fd56d0edb808ab15a_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 2439512362619, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 6954924882, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": [], + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002fd10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102cc08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001028d0a0a08000106307375323433393531323336323631397264393230376165353763616236333366643536643065646238303861623135611a0900010a0602414c1630737532343339353132333632363139726439323037616535376361623633336664353664306564623830386162313561261e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f36042e666c76461e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f56052e6d3375386003790c8c9600a600bcccd90ce019f00f19f01019f61100f81200020603666c761a0603666c76161e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f26042e666c76390c4001506466007c0b0603686c731a0603686c73161e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f26052e6d337538390c40015c663369643d7375323433393531323336323631397264393230376165353763616236333366643536643065646238303861623135617c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c6300000237fe448e7b7c81192d9006a103e8b103e8c103e8d600e60861707069643d38310b0b160a36393534393234383832260a36393534393234383832325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "freefire" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1034, + "superscriptType": 0, + "anchorCountryCode": "CO", + "fps": null, + "anchorAnnouncement": "Si te gusta lo épico, tienes que ver esto!!\uD83D\uDE31", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201910151571108592514_2439512362619_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201910151571108592514_2439512362619_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201910151571108592514_2439512362619_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": 6865196808284081658, + "microPKStatus": 0, + "userId": null, + "roomTheme": "GOOO", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "mrstiventc", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 12132, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 760109, + "sharpness": null, + "roomType": 25, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1599511644533/202006081591601657620_1599511644533_avatar.png", + "roomTypeName": "无尽对决", + "isLottery": 0, + "anchorId": 1599511644533, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1569227722000, + "anchorLabelType": 1, + "labelId": 11, + "labelNameLang": "", + "sort": 420, + "labelName": "技術流", + "type": 4 + }, + { + "timeStamp": 1569227722000, + "anchorLabelType": 1, + "labelId": 9, + "labelNameLang": "", + "sort": 420, + "labelName": "顏值", + "type": 4 + } + ], + "roomSort": 0, + "lcidText": "Bahasa Indonesia", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "EVOS Earl", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/C58F01BDAE27C0E69A9F06C4EDB57C23_013c51274385f32a837b869fd81f4f91.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/709C3E18BD4BEE85096CB4A09F700F7A_0cee470064b1fec1b4bb2f86804a2e9e.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/660DE5409F7FE56C6F0A8257E171CE0C_0bca4c36bed15a58e8a34e12421a9f8a.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511644533r80682fa1ba485fa43bd790a51d4e4f6c_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599511644533, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 760109, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": [], + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002ed10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102bc08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001027d0a0a08000106307375313539393531313634343533337238303638326661316261343835666134336264373930613531643465346636631a0900010a060257531630737531353939353131363434353333723830363832666131626134383566613433626437393061353164346534663663261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce019f00f19f01019f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531313634343533337238303638326661316261343835666134336264373930613531643465346636637c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c63000001746a52c9757c8114d79006a103e8b103e8c103e8d600e60861707069643d38310b0b16063736303130392606373630313039325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "mlbb" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1057, + "superscriptType": 0, + "anchorCountryCode": "ID", + "fps": null, + "anchorAnnouncement": "FOLLOW MY INSTAGRAM @windalunardi\nDon't forget to hit the follow button!", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "MAIN APA NIH", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "evosearl", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 8489, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 79438019, + "sharpness": null, + "roomType": 79, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1639514062140/202007121594528366427_1639514062140_avatar.png", + "roomTypeName": "電腦遊戲", + "isLottery": 0, + "anchorId": 1639514062140, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1569573983000, + "anchorLabelType": 1, + "labelId": 11, + "labelNameLang": "", + "sort": 420, + "labelName": "技術流", + "type": 4 + }, + { + "timeStamp": 1569573983000, + "anchorLabelType": 1, + "labelId": 8, + "labelNameLang": "", + "sort": 420, + "labelName": "幽默", + "type": 4 + } + ], + "roomSort": 0, + "lcidText": "Tiếng Việt", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "QNT", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/7CCE7B73C8E9CBE2C1CC5D7997D9197A_f1f54039870b56ec6b9db1679ccdf8d0.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/2B489EDAB5F2202622E943C32E86EF6C_b38e40077501fde7604ba12cad4e9cd6.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/F2BA7C08617E45D895FE59BEF4EF3831_da98febc02b1c042dd90b774aff18f15.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639514062140r44b21ec24b2ac6f0e82e688ed31267cb_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1639514062140, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 79438019, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": [], + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313633393531343036323134307234346232316563323462326163366630653832653638386564333132363763621a0900010a060257531630737531363339353134303632313430723434623231656332346232616336663065383265363838656433313236376362261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313633393531343036323134307234346232316563323462326163366630653832653638386564333132363763627c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c630000017dbaa73d3c7c81180f9001a103e8b103e8c103e8d600e60861707069643d38310b0b1608373934333830313926083739343338303139325f461f9d0b8c980ca80c", + "gameAbbrList": null, + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1066, + "superscriptType": 0, + "anchorCountryCode": "VN", + "fps": null, + "anchorAnnouncement": "✅ DONATE:\n Paypal: https://streamlabs.com/blueb2 \n* https://playerduo.com/quangngoctrinh\n\nLink offer: https://steamcommunity.com/tradeoffer/new/?partner=457474386&token=VjTmUImS\nLink Fb: https://www.facebook.com/bluebvn\nLink Fanpage: https://www.facebook.com/quangngoctri...\nLink Group: https://www.facebook.com/groups/clubq...\nLink Discord: https://discord.gg/7bg2TkE", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201907111562877225213_1639514062140_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201907111562877225213_1639514062140_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201907111562877225226_1639514062140_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "What's up Homies ?", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "qntofficial", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 6684, + "onlineStatus": 0, + "endLiveTime": 1598403724, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 56092595, + "sharpness": null, + "roomType": 25, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201901061546776316027-56092595_avatar.png", + "roomTypeName": "无尽对决", + "isLottery": 0, + "anchorId": 1599512191936, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "Bahasa Indonesia", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "AEROWOLF KIDO", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/F1DB228D6F3813442643D8308CDB6AA3_c9668de4cba90edc63ba8d09818d5fb0.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/BAEB9F361A943A9D0CE4EB39CEDA4954_63f3db000f914b518d769f843c056928.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/667ECD636D02A9521B6665FC3E05B824_1d9d80a4a7df45546151b1dccf19aa1d.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512191936rb351b4d9ad63b9765bd38de291fad91c_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1599512191936, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 56092595, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002cb10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d0001029a08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001025b0a0a08000106307375313539393531323139313933367262333531623464396164363362393736356264333864653239316661643931631a0900010a060257531630737531353939353132313931393336726233353162346439616436336239373635626433386465323931666164393163261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce019f00f19f01019f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531323139313933367262333531623464396164363362393736356264333864653239316661643931637c0b0b1900040a0604373230701c2c30ff4a0105001102d00b56086e656564776d3d30680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b2601303c46005c63000001746a5b23c07c81057b9006a103e8b103e8c103e8d600e60861707069643d38310b0b1608353630393235393526083536303932353935325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "mlbb" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1057, + "superscriptType": 0, + "anchorCountryCode": "ID", + "fps": null, + "anchorAnnouncement": "Hi! I am a new streamer of Nimo. Hope you enjoy my livestream and feel free to tap that \"Follow\" button!", + "showScreenshots": null, + "follow": null, + "liveId": 6865091725753862940, + "microPKStatus": 0, + "userId": null, + "roomTheme": "RUSEL MENGOLAH PATCH BARU!", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "kido", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 6567, + "onlineStatus": 0, + "endLiveTime": 1598430012, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 11884028, + "sharpness": null, + "roomType": 9, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1599513340263/202007061594039785623_1599513340263_avatar.png", + "roomTypeName": "GTA5", + "isLottery": 0, + "anchorId": 1599513340263, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "ไทย", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "MoDra", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/140C3C2F20B5D547A4E181842206FBE5_500x280.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/B8714692160BD1DBA082ED0D93901ABB_338x190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/E423BE73521FB8160A4557415D974236_136x76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_high.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513340263rc66caa18c80b4735400efea861a47d35_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1599513340263, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 11884028, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f110022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c008000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102810a0a08000106307375313539393531333334303236337263363663616131386338306234373335343030656665613836316134376433351a0900010a0602414c1630737531353939353133333430323633726336366361613138633830623437333534303065666561383631613437643335261b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386003790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531333334303236337263363663616131386338306234373335343030656665613836316134376433357c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c63000001746a6ca9677c81183a9003a103e8b103e8c103e8d600e60861707069643d38310b0b1608313138383430323826083131383834303238325f4620050b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "gta5" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1054, + "superscriptType": 0, + "anchorCountryCode": "TH", + "fps": null, + "anchorAnnouncement": "Donate:0201714508[กสิกร]ธนพล\n\nCPU:Intel®Core™i9-9900ksM/B:ROGSTRIXZ390-EGAMINGRAM:64.00GBVGA:NVIDIAGeForceRTX2080TiMonitor:BenqXL2546(240Hz)Monitor2:BenqXL2411Z(144Hz)\n\nFacebook : ธนพล สาพะพิพัฒน์พงษ์ \nPage : MoDra\nYoutube : MoDra Official", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201905291559111462700_1599513340263_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201905291559111462700_1599513340263_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201905291559111462700_1599513340263_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": 6865204631747609017, + "microPKStatus": 0, + "userId": null, + "roomTheme": "อะจ้ากกกก", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "modra", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 5710, + "onlineStatus": 0, + "endLiveTime": 1598425486, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 117909682, + "sharpness": null, + "roomType": 25, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/202003161584340023169_1599514396441_avatar.png", + "roomTypeName": "无尽对决", + "isLottery": 0, + "anchorId": 1599514396441, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "Bahasa Indonesia", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "pixisye", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/B54FF40C106E4006522424AA8EF6E977_494df88d6a61d7a282cd34b521762461.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/761333E325B2B89EACA3E63F2EC74D44_1ff2b039c69e4252117a7dbfdaffb2e4.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/3435A9070E674C12E66D6C1A42CB986E_941853d7677634fb4e0b0b6c5fc2508d.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_high.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514396441ra36b85a8252413bfc928d8d26c560e98_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599514396441ra36b85a8252413bfc928d8d26c560e98_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599514396441, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 117909682, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313539393531343339363434317261333662383561383235323431336266633932386438643236633536306539381a0900010a060254581630737531353939353134333936343431726133366238356138323532343133626663393238643864323663353630653938261b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386005790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531343339363434317261333662383561383235323431336266633932386438643236633536306539387c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c63000001746a7cc7197c810c5f9006a103e8b103e8c103e8d600e60861707069643d38310b0b16093131373930393638322609313137393039363832325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "mlbb" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1057, + "superscriptType": 0, + "anchorCountryCode": "ID", + "fps": null, + "anchorAnnouncement": "IG @shyrnsnts\nLink donate : sociabuzz.com/pixisye/donate\nChannel Youtube : Shyeren San", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201910151571153059286_1599514396441_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201910151571153059286_1599514396441_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201910151571153059286_1599514396441_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": 6865185189716661235, + "microPKStatus": 0, + "userId": null, + "roomTheme": "HALO", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "shyerensan", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 3598, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 1883325243, + "sharpness": null, + "roomType": 30, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201912271577479461933_1939512525499_avatar.png", + "roomTypeName": "我要活下去", + "isLottery": 0, + "anchorId": 1939512525499, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "Español ", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "A3 Sag", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/3B1E5ED53423466423938C24144C51BD_536b289be97350bb51b88ef01d959c81.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/CA9247CB612D19F81B73DEB2F0FFF8D7_cd5242a18fda4f96154cdd33251fde41.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/13EEEC4E6C96A708373A3F02BE6B8359_7f324d7e7ff201cdc5d82edb06b2e21e.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1939512525499r46836b6ca96f1852f502c49972a963d7_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1939512525499r46836b6ca96f1852f502c49972a963d7_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1939512525499, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 1883325243, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f710022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c608000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102870a0a08000106307375313933393531323532353439397234363833366236636139366631383532663530326334393937326139363364371a0900010a060257531630737531393339353132353235343939723436383336623663613936663138353266353032633439393732613936336437261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313933393531323532353439397234363833366236636139366631383532663530326334393937326139363364377c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c63000001c393f482bb7c8124179001a103e8b103e8c103e8d600e60861707069643d38310b0b160a31383833333235323433260a31383833333235323433325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "freefire" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1034, + "superscriptType": 0, + "anchorCountryCode": "MX", + "fps": null, + "anchorAnnouncement": "Sigueme en Instagram: @a3sagx", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "VUELVEN LAS CLASFICATORIAS!", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "a3saglive", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 3274, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 38642090, + "sharpness": null, + "roomType": 79, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201907111562862289255_1599514153662_avatar.png", + "roomTypeName": "電腦遊戲", + "isLottery": 0, + "anchorId": 1599514153662, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1569574045000, + "anchorLabelType": 1, + "labelId": 11, + "labelNameLang": "", + "sort": 420, + "labelName": "技術流", + "type": 4 + } + ], + "roomSort": 0, + "lcidText": "Tiếng Việt", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "FunkyM", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/F364C10E4681A4F5FA52CAD3CF7D613B_5dba7a0d7ea5e500ac0f06d2cf87a58a.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/8D5571C79B9F849153CBF070A438AC43_9fbb3648a84a5865cf4f364f5f39bfee.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/7AD6CAF61FD6E8F644AF9AEC43D29AEE_596689b6653f72f2cddc4881104c7817.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599514153662rd763d8fce009d0cd5fa0f621b2a13187_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599514153662, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 38642090, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": [], + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313539393531343135333636327264373633643866636530303964306364356661306636323162326131333138371a0900010a060257531630737531353939353134313533363632726437363364386663653030396430636435666130663632316232613133313837261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531343135333636327264373633643866636530303964306364356661306636323162326131333138377c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c63000001746a7912be7c811ba89003a103e8b103e8c103e8d600e60861707069643d38310b0b1608333836343230393026083338363432303930325f4620630b8c980ca80c", + "gameAbbrList": null, + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1066, + "superscriptType": 0, + "anchorCountryCode": "VN", + "fps": null, + "anchorAnnouncement": "■ Chúc anh em xem stream vui vẻ !!!\n\n■ Lịch Live : 12h - 4h hàng ngày\n\n■ Ủng hộ mình tại : \n\n * https://qr.wescan.vn/Funky\n\n * https://streamlabs.com/funky\n\n * https://playerduo.com/funky", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "FunkyM | Stream là cái duyên", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "funkym", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 2698, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 60263246, + "sharpness": null, + "roomType": 9, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201906131560416780696_1599512687360_avatar.png", + "roomTypeName": "GTA5", + "isLottery": 0, + "anchorId": 1599512687360, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "ไทย", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "starix", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/6692AE8CA73BC8DE67291082FBB7889B_4c244161642d1c58f87cf2ddbfbf829b.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/D8471B51134BE16AFB1EE69B9C5E20BC_a1c39548ebc87c311cb197fd71753b0b.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/2A1FA5519BF3C64252A21BF5094E26D6_520858d29144445a72b8e1375c03f7d0.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512687360r3b7538628b50dc5856c9bde793f32ac9_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599512687360, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 60263246, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313539393531323638373336307233623735333836323862353064633538353663396264653739336633326163391a0900010a060257531630737531353939353132363837333630723362373533383632386235306463353835366339626465373933663332616339261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531323638373336307233623735333836323862353064633538353663396264653739336633326163397c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c63000001746a62b3007c8118069003a103e8b103e8c103e8d600e60861707069643d38310b0b1608363032363332343626083630323633323436325f46205b0b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "gta5" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1054, + "superscriptType": 0, + "anchorCountryCode": "TH", + "fps": null, + "anchorAnnouncement": "สวัสดี!ฉันเป็นสตรีมเมอร์รายใหม่หวังว่าทุกคนจะเพลิดเพลินไปกับการLiveStreamของฉันและอย่าลืมที่จะกดปุ่มติดตามเป็นกำลังใจให้กันด้วยนะ!", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201907071562482975888_1599512687360_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201907071562482975888_1599512687360_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201907071562482975895_1599512687360_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "หมอออออออจ๋า", + "anchorSex": 0, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "starix", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 2153, + "onlineStatus": 0, + "endLiveTime": 1598430353, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 1, + "createdTime": null, + "id": 45383103, + "sharpness": null, + "roomType": 25, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201907121562919751502_1599512387843_avatar.png", + "roomTypeName": "无尽对决", + "isLottery": 0, + "anchorId": 1599512387843, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1598431322773, + "anchorLabelType": 2, + "labelId": 15, + "labelNameLang": "", + "sort": 130, + "labelName": "競猜", + "type": 1 + } + ], + "roomSort": 2, + "lcidText": "Bahasa Indonesia", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Onic Antimage", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/6EAC450A5F054826E766048B5B73038C_2cb7565636e89d2be91f1b4125395730.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/7570BDC9DF86907BCDE8AC5F9DFFE342_f04d7dc22b192665f1b367a5504e20f7.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/79876378D1CFAF5B4160A56E035DDCE9_5575db9aaa1d6648d67bd593ff973e64.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599512387843re6fc3b824d373b9bcb81c368c7d61699_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1599512387843, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 45383103, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": "競猜", + "expireLabelIds": [], + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f110022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c008000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102810a0a08000106307375313539393531323338373834337265366663336238323464333733623962636238316333363863376436313639391a0900010a060257531630737531353939353132333837383433726536666333623832346433373362396263623831633336386337643631363939261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531323338373834337265366663336238323464333733623962636238316333363863376436313639397c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c63000001746a5e21037c810c4e9003a103e8b103e8c103e8d600e60861707069643d38310b0b1608343533383331303326083435333833313033325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "mlbb" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1057, + "superscriptType": 3, + "anchorCountryCode": "ID", + "fps": null, + "anchorAnnouncement": "Official Livestream Channel of ONIC AntiMage\nFollow my Instagram: @maxhill.leonardo", + "showScreenshots": null, + "follow": null, + "liveId": 6865206097155693935, + "microPKStatus": 0, + "userId": null, + "roomTheme": "FULL ONIC WAJIB MILITER COKKKK", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "antimage", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1907, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 6464669354, + "sharpness": null, + "roomType": 10, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201911031572807529070_2399514356034_avatar.png", + "roomTypeName": "League of Legends", + "isLottery": 0, + "anchorId": 2399514356034, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "Português", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "mandiocaa1", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399514356034r6df8ad8d506c08b29080a7651f5e49b6_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 2399514356034, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 6464669354, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f510022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c408000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102850a0a08000106307375323339393531343335363033347236646638616438643530366330386232393038306137363531663565343962361a0900010a060254581630737532333939353134333536303334723664663861643864353036633038623239303830613736353166356534396236261b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386005790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375323339393531343335363033347236646638616438643530366330386232393038306137363531663565343962367c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c630000022eae3369427c8115fd9006a103e8b103e8c103e8d600e60861707069643d38310b0b160a36343634363639333534260a36343634363639333534325f461f9d0b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "lol" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1046, + "superscriptType": 0, + "anchorCountryCode": "BR", + "fps": null, + "anchorAnnouncement": "GRULI GRULI\n\nPra donatar pro papi segue o link:\nhttps://streamlabs.com/mandiocaa/tip\n\nSegue o papi nas redes sociais:\nInsta: https://www.instagram.com/mandiocaalol/?hl=pt-br\nTwitter: https://twitter.com/mandiocaalol\n\nDiscord:\nhttps://discord.gg/VR2RrUN\n\nLink para inscrição do camp de x1 dos subs:\nhttps://docs.google.com/forms/d/e/1FAIpQLSf4SxFmPd5rEE0SgnLB2KAsAGHiD6l0g-gbAzxK0yJcP4suqQ/viewform", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "continuando o unranked ao chal", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "mandioquinha", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1839, + "onlineStatus": 0, + "endLiveTime": 1598404506, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 6511265628, + "sharpness": null, + "roomType": 9, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/2399515724630/202006171592373730927_2399515724630_avatar.png", + "roomTypeName": "GTA5", + "isLottery": 0, + "anchorId": 2399515724630, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "Español ", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Micaelala", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/1F393C8526AECDB85D3EF6DBF73892DB_2cb7565636e89d2be91f1b4125395730.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/5E9EA503C6BC941DCDD016BCD024F495_f04d7dc22b192665f1b367a5504e20f7.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/656D30BFD55D839BA280C602FF8CBDA9_5575db9aaa1d6648d67bd593ff973e64.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/backsrc/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515724630rd94dc79182ac027af31391cdcfdd6bb0_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 2399515724630, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 6511265628, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002fb10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102ca08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001028b0a0a08000106307375323339393531353732343633307264393464633739313832616330323761663331333931636463666464366262301a0900010a0602414c1630737532333939353135373234363330726439346463373931383261633032376166333133393163646366646436626230261e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f36042e666c76461e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f56052e6d3375386003790c8c9600a600bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f26042e666c76390c4001506466007c0b0603686c731a0603686c73161e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f26052e6d337538390c40015c663369643d7375323339393531353732343633307264393464633739313832616330323761663331333931636463666464366262307c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c630000022eae484b567c8110359001a103e8b103e8c103e8d600e60861707069643d38310b0b160a36353131323635363238260a36353131323635363238325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "gta5" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1034, + "superscriptType": 0, + "anchorCountryCode": "AR", + "fps": null, + "anchorAnnouncement": "Hola! Venite que empezó la fiesta", + "showScreenshots": null, + "follow": null, + "liveId": 6865095082349102739, + "microPKStatus": 0, + "userId": null, + "roomTheme": "COMIENZO EN LA NIEVE", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "micaelala", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1811, + "onlineStatus": 0, + "endLiveTime": 1598418502, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 4918902, + "sharpness": null, + "roomType": 9, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1599517054627/202008181597722817419_1599517054627_avatar.png", + "roomTypeName": "GTA5", + "isLottery": 0, + "anchorId": 1599517054627, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "ไทย", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "MEYOU", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su1599517054627rcaa69f86376d8ae896be27b5d77af36e.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517054627rcaa69f86376d8ae896be27b5d77af36e_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599517054627, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 4918902, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f110022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c008000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102810a0a08000106307375313539393531373035343632377263616136396638363337366438616538393662653237623564373761663336651a0900010a060257531630737531353939353137303534363237726361613639663836333736643861653839366265323762356437376166333665261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531373035343632377263616136396638363337366438616538393662653237623564373761663336657c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c63000001746aa556a37c81182b9003a103e8b103e8c103e8d600e60861707069643d38310b0b160734393138393032260734393138393032325f46205b0b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "gta5" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1054, + "superscriptType": 0, + "anchorCountryCode": "TH", + "fps": null, + "anchorAnnouncement": "• ชื่อ Icezy อายุ 18 •\n• FB :Piyada promhong ( พิยะ ดา ) •\n• FP : Ice Piyada \uD83E\uDDF8•", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/202008191597843339930_1599517054627_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/202008191597843339930_1599517054627_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/202008191597843339930_1599517054627_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": 6865155193981157979, + "microPKStatus": 0, + "userId": null, + "roomTheme": "MEYOU", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": null, + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1409, + "onlineStatus": 0, + "endLiveTime": 1598426214, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 77738266, + "sharpness": null, + "roomType": 9, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1599513640021/202007271595882369734_1599513640021_avatar.png", + "roomTypeName": "GTA5", + "isLottery": 0, + "anchorId": 1599513640021, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "ไทย", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "JUNIOR", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/64A6B6D8E31E0E645067CF61A9D10504_e276de31f2ed61e1116fda1a461175d9.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/8B7DDC2A7604FFE52EB30F98AB2D5111_b50dc3fe0c759fa95214e2f52a823a71.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/7F37DA485183ED1B7944495B6A9AFA9B_14acc28ad0e2d4783a5c32c3bcf54320.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_high.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599513640021rf1aab3c638203e000b08bcc59ff3361b_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1599513640021, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 77738266, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f110022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c008000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102810a0a08000106307375313539393531333634303032317266316161623363363338323033653030306230386263633539666633333631621a0900010a060257531630737531353939353133363430303231726631616162336336333832303365303030623038626363353966663333363162261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531333634303032317266316161623363363338323033653030306230386263633539666633333631627c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c63000001746a713c557c8114b29003a103e8b103e8c103e8d600e60861707069643d38310b0b1608373737333832363626083737373338323636325f46205b0b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "gta5" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1054, + "superscriptType": 0, + "anchorCountryCode": "TH", + "fps": null, + "anchorAnnouncement": "\uD83D\uDC9Aสลัดเองฮ้ะ\uD83D\uDC9A\n------------------------------------\n\uD83D\uDC9AFB : Junior Tanapon\uD83D\uDC9A\n \uD83D\uDC9AYoutube : JUNIOR\uD83D\uDC9A\n------------------------------------\nhttps://www.youtube.com/channel/UCDYGsTQbvva5vTZjGobTRMA", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/202007121594561049048_1599513640021_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/202007121594561049048_1599513640021_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/202007121594561049048_1599513640021_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": 6865188320526927057, + "microPKStatus": 0, + "userId": null, + "roomTheme": "เจ้าจูเนียร์มาแว้ววว", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "junior", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1325, + "onlineStatus": 0, + "endLiveTime": 1598425178, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 170064411, + "sharpness": null, + "roomType": 9, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201904111554970812380_1629512282901_avatar.png", + "roomTypeName": "GTA5", + "isLottery": 0, + "anchorId": 1629512282901, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "ไทย", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Porto", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/F29300E6C7E741F2C8B70BE187BBA47_e541ea5323a1cc31af8d8bfe214927ba.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/BB158101A11C94088BA1392AAE51D9D_f04d7dc22b192665f1b367a5504e20f7.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/9CDE553210CA53AF2633AE3FB5EF7CC0_5575db9aaa1d6648d67bd593ff973e64.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_high.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1629512282901r2c57f26e42b17e9e8481c8108c6e6696_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1629512282901, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 170064411, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f510022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c408000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102850a0a08000106307375313632393531323238323930317232633537663236653432623137653965383438316338313038633665363639361a0900010a0602414c1630737531363239353132323832393031723263353766323665343262313765396538343831633831303863366536363936261b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386003790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313632393531323238323930317232633537663236653432623137653965383438316338313038633665363639367c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c630000017b668033157c8117f39003a103e8b103e8c103e8d600e60861707069643d38310b0b16093137303036343431312609313730303634343131325f46205b0b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "gta5" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1054, + "superscriptType": 0, + "anchorCountryCode": "TH", + "fps": null, + "anchorAnnouncement": "•Facebookwww.facebook.com/Portornp\n•Fanpagehttps://www.facebook.com/Portobrot/•Youtubehttps://1th.me/Porto", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201905181558188800756_1629512282901_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201905181558188800756_1629512282901_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201905181558188800747_1629512282901_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": 6865183867127515242, + "microPKStatus": 0, + "userId": null, + "roomTheme": "อย่า!!!", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "porto", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1258, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 1, + "createdTime": null, + "id": 526550, + "sharpness": null, + "roomType": 3, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1599511699076/202008211598001239886_1599511699076_avatar.png", + "roomTypeName": "絶地求生", + "isLottery": 0, + "anchorId": 1599511699076, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1598431321705, + "anchorLabelType": 2, + "labelId": 15, + "labelNameLang": "", + "sort": 130, + "labelName": "競猜", + "type": 1 + } + ], + "roomSort": 0, + "lcidText": "Tiếng Việt", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "DxG_FerGus", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su1599511699076r2987fe70a9042fd839dea35b0eb78244.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su1599511699076r2987fe70a9042fd839dea35b0eb78244_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su1599511699076r2987fe70a9042fd839dea35b0eb78244_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1599511699076r2987fe70a9042fd839dea35b0eb78244_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599511699076r2987fe70a9042fd839dea35b0eb78244_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599511699076, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 526550, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": "競猜", + "expireLabelIds": [], + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "0000030b10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102da08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001029b0a0a08000106307375313539393531313639393037367232393837666537306139303432666438333964656133356230656237383234341a0900010a0602414c1630737531353939353131363939303736723239383766653730613930343266643833396465613335623065623738323434261e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f36042e666c76461e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f56052e6d3375386003790c8c9600a600bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f26042e666c76390c4001506466007c0b0603686c731a0603686c73161e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f26052e6d337538390c40015c663369643d7375313539393531313639393037367232393837666537306139303432666438333964656133356230656237383234347c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2610313836333737373939343036323033383c46005300069f18a146b8d663000001746a539e8470038115c39001a103e8b103e8c103e8d600e60861707069643d38310b0b16063532363535302606353236353530325f461fcd0b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "pubg" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1066, + "superscriptType": 3, + "anchorCountryCode": "SG", + "fps": null, + "anchorAnnouncement": "Link donate or thuê:Playerduo.com/simvc1\nLink FB cá nhân:https://www.facebook.com/SimVC170\nFanpage FB:https://www.facebook.com/NiMo-TV-Simvc1702-563534494059597/?modal=admin_todo_tour", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201905171558054199519_1599511699076_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201905171558054199519_1599511699076_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201905171558054199496_1599511699076_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "DxG_FerGus #PoPesports", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": null, + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1227, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 189781752, + "sharpness": null, + "roomType": 21, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1639516877982/202008171597682665188_1639516877982_avatar.png", + "roomTypeName": "PUBG Mobile", + "isLottery": 0, + "anchorId": 1639516877982, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 2, + "lcidText": "Bahasa Indonesia", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "BTR Kyra", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/7835619239C452AA92B0F6E55702E6B2_e4091f4a684a64afff76566655ad9aa4.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/DF90F9E6B7071470ADB426259EF496E6_7ee8ca6ca986414886ba86573bf3de5c.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/B981400524D77C7A4A4CBEC96D48900A_f5c3e6e3b445946433ab5bb96c6365cc.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639516877982r72417f8d9842b2c9507dad6e259a9a19_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1639516877982, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 189781752, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313633393531363837373938327237323431376638643938343262326339353037646164366532353961396131391a0900010a0602414c1630737531363339353136383737393832723732343137663864393834326232633935303764616436653235396139613139261b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386003790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313633393531363837373938327237323431376638643938343262326339353037646164366532353961396131397c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c630000017dbad2349e7c810a609003a103e8b103e8c103e8d600e60861707069643d38310b0b16093138393738313735322609313839373831373532325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "pubgmobile" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1057, + "superscriptType": 0, + "anchorCountryCode": "ID", + "fps": null, + "anchorAnnouncement": "Hello guysss, welcome!! :)\nAku live hampir setiap hari jam 14.00-18.00 atau jam 22.00-02.00\nJangan lupa follow yaa biar ga ketinggalan live stream aku :D\nThankyou guys <3", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "pabjieh", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": null, + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1169, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 5547720948, + "sharpness": null, + "roomType": 10, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1999513396858/202005091589045319159_1999513396858_avatar.png", + "roomTypeName": "League of Legends", + "isLottery": 0, + "anchorId": 1999513396858, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "Türkçe", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Oguz Aslan", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/2958B342EF5D3878539EE89874E21E6A_edd0efeef1b36c38bdce5741ef06392c.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/44D84809B7DE0B43BD9CEA932B1250FF_436714b917a18232b42dfd799c1da418.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/96EDF1D0EE93BFABAA7C2130ECF87BC7_390cd719ba043443ceba21d847b40b6f.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1999513396858r0361c24cd5afd9973a8aec71938bcd51_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1999513396858, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 5547720948, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002cf10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d0001029e08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001025f0a0a08000106307375313939393531333339363835387230333631633234636435616664393937336138616563373139333862636435311a0900010a060257531630737531393939353133333936383538723033363163323463643561666439393733613861656337313933386263643531261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313939393531333339363835387230333631633234636435616664393937336138616563373139333862636435317c0b0b1900040a0604373230701c2c30ff4a0105001102d00b56086e656564776d3d30680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b2601303c46005c63000001d18c49267a7c8108ae9001a103e8b103e8c103e8d600e60861707069643d38310b0b160a35353437373230393438260a35353437373230393438325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "lol" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1055, + "superscriptType": 0, + "anchorCountryCode": "TR", + "fps": null, + "anchorAnnouncement": "Merhaba, ben Oğuz Aslan sizi efsane bir yayın bekliyor takipte kalın ve maceranın tadını çıkarın", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "sabah lolü", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "oguzaslan", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1090, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 5071172470, + "sharpness": null, + "roomType": 21, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/2039513721969/202008211598023381311_2039513721969_avatar.png", + "roomTypeName": "PUBG Mobile", + "isLottery": 0, + "anchorId": 2039513721969, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "Türkçe", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Kadir Çakmak", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su2039513721969r72c711eb72df939125091407b524ac42.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su2039513721969r72c711eb72df939125091407b524ac42_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su2039513721969r72c711eb72df939125091407b524ac42_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2039513721969r72c711eb72df939125091407b524ac42_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2039513721969r72c711eb72df939125091407b524ac42_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 2039513721969, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 5071172470, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002fb10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102ca08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001028b0a0a08000106307375323033393531333732313936397237326337313165623732646639333931323530393134303762353234616334321a0900010a0602414c1630737532303339353133373231393639723732633731316562373264663933393132353039313430376235323461633432261e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f36042e666c76461e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f56052e6d3375386003790c8c9600a600bcccd90ce019f00f19f01019f61100f81200020603666c761a0603666c76161e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f26042e666c76390c4001506466007c0b0603686c731a0603686c73161e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f26052e6d337538390c40015c663369643d7375323033393531333732313936397237326337313165623732646639333931323530393134303762353234616334327c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c63000001dadc7dac717c810f7d9006a103e8b103e8c103e8d600e60861707069643d38310b0b160a35303731313732343730260a35303731313732343730325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "pubgmobile" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1055, + "superscriptType": 0, + "anchorCountryCode": "TR", + "fps": null, + "anchorAnnouncement": "Merhaba! Ben Kadir Çakmak Nimo TV'daki yeni bir yayıncıyım. Umarım benim kanalımın tadını çıkarır ve bu \"Takip et\" düğmesine tıklamakta özgürsünüz!", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "FURY DELYKADİR SABAH YARGISI !", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "kadircakmak", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": 0, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1061, + "onlineStatus": 0, + "endLiveTime": 1598427614, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 1, + "createdTime": null, + "id": 87052500, + "sharpness": null, + "roomType": 10, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1599517046720/202007291595994304043_1599517046720_avatar.png", + "roomTypeName": "League of Legends", + "isLottery": 0, + "anchorId": 1599517046720, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1598431324516, + "anchorLabelType": 2, + "labelId": 15, + "labelNameLang": "", + "sort": 130, + "labelName": "競猜", + "type": 1 + } + ], + "roomSort": 0, + "lcidText": "Tiếng Việt", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "gaybestleesin", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/DFDFCEDEECB5C2756800940C61FC1978_2cb7565636e89d2be91f1b4125395730.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/91A8588CCDB122084833ACFC17BA6BED_f04d7dc22b192665f1b367a5504e20f7.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/8F5EC43FB249F757F12E497291463561_5575db9aaa1d6648d67bd593ff973e64.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_high.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599517046720rf319020d9cd5c339a0118107e9bbb8dd_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599517046720, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 87052500, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": "競猜", + "expireLabelIds": [], + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313539393531373034363732307266333139303230643963643563333339613031313831303765396262623864641a0900010a0602414c1630737531353939353137303436373230726633313930323064396364356333333961303131383130376539626262386464261b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386003790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531373034363732307266333139303230643963643563333339613031313831303765396262623864647c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c63000001746aa537c07c8118699003a103e8b103e8c103e8d600e60861707069643d38310b0b1608383730353235303026083837303532353030325f461f9d0b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "lol" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1066, + "superscriptType": 3, + "anchorCountryCode": "VN", + "fps": null, + "anchorAnnouncement": "Hello các bạn mình là Gầy đây hihiihihi !\nDonate cho mình tại : https://playerduo.com/gaybestleesin", + "showScreenshots": null, + "follow": null, + "liveId": 0, + "microPKStatus": 0, + "userId": null, + "roomTheme": "Gầy Best leesin", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "gaybestleesin", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 1024, + "onlineStatus": 0, + "endLiveTime": 1598418008, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 6046224575, + "sharpness": null, + "roomType": 9, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/202004091586427775644_2449511675549_avatar.png", + "roomTypeName": "GTA5", + "isLottery": 0, + "anchorId": 2449511675549, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "Español ", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "rayitoo", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su2449511675549rede6329d2b1d1f522310fa415ca608cf.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su2449511675549rede6329d2b1d1f522310fa415ca608cf_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su2449511675549rede6329d2b1d1f522310fa415ca608cf_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2449511675549rede6329d2b1d1f522310fa415ca608cf_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2449511675549rede6329d2b1d1f522310fa415ca608cf_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 2449511675549, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 6046224575, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002fb10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102ca08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001028b0a0a08000106307375323434393531313637353534397265646536333239643262316431663532323331306661343135636136303863661a0900010a0602414c1630737532343439353131363735353439726564653633323964326231643166353232333130666134313563613630386366261e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f36042e666c76461e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f56052e6d3375386003790c8c9600a600bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f26042e666c76390c4001506466007c0b0603686c731a0603686c73161e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f26052e6d337538390c40015c663369643d7375323434393531313637353534397265646536333239643262316431663532323331306661343135636136303863667c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c630000023a5245f69d7c810ad29001a103e8b103e8c103e8d600e60861707069643d38310b0b160a36303436323234353735260a36303436323234353735325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "gta5" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1034, + "superscriptType": 0, + "anchorCountryCode": "AR", + "fps": null, + "anchorAnnouncement": "instagram: rayogovir", + "showScreenshots": null, + "follow": null, + "liveId": 6865153072090206814, + "microPKStatus": 0, + "userId": null, + "roomTheme": "GTA DOVUX", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "rayitoo", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": 0, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 994, + "onlineStatus": 0, + "endLiveTime": 1598412200, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 6297374112, + "sharpness": null, + "roomType": 30, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/202003311585614230831_2439514083187_avatar.png", + "roomTypeName": "我要活下去", + "isLottery": 0, + "anchorId": 2439514083187, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "Português", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "INTZ BRANCA", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2439514083187rd44cdb00c2ea111d5ade7acffabbe143_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 2439514083187, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 6297374112, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f710022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c608000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102870a0a08000106307375323433393531343038333138377264343463646230306332656131313164356164653761636666616262653134331a0900010a060254581630737532343339353134303833313837726434346364623030633265613131316435616465376163666661626265313433261b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386005790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375323433393531343038333138377264343463646230306332656131313164356164653761636666616262653134337c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c6300000237fe5ecf737c81224f9006a103e8b103e8c103e8d600e60861707069643d38310b0b160a36323937333734313132260a36323937333734313132325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "freefire" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1046, + "superscriptType": 0, + "anchorCountryCode": "BR", + "fps": null, + "anchorAnnouncement": "Oi galera, bem vindos! ❤\n\nSou a Branca, Jogadora Profissional de Free Fire pela INTZ.\n\nLives todos os dias, entre 00h ~ 05h.\n\nInstagram: @brancatv\nYoutube: Branca TV\nDiscord: https://discord.gg/XWs63CQ", + "showScreenshots": null, + "follow": null, + "liveId": 6865128132287610643, + "microPKStatus": 0, + "userId": null, + "roomTheme": "X1 DOS CRIAS, BORA", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "brancatv", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 978, + "onlineStatus": 0, + "endLiveTime": 1598430480, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 2507703, + "sharpness": null, + "roomType": 25, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1639517185272/202007141594706842295_1639517185272_avatar.png", + "roomTypeName": "无尽对决", + "isLottery": 0, + "anchorId": 1639517185272, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1598431326173, + "anchorLabelType": 3, + "labelId": 83, + "labelNameLang": "", + "sort": 210, + "labelName": "Kimmy", + "type": 2 + } + ], + "roomSort": 0, + "lcidText": "Bahasa Indonesia", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "S A N Z", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/D6ACF66BCDE4D2CF3B5DC6643BD6A89B_2cb7565636e89d2be91f1b4125395730.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/16810EE9116F433F3685E5719B827E12_f04d7dc22b192665f1b367a5504e20f7.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/F13C1320BBD497BC5F0A7DB6A8468525_5575db9aaa1d6648d67bd593ff973e64.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1639517185272rc346f7e84185bed9527154d2a48f45b9_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1639517185272, + "bIfLiveInter": true, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 2507703, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": [], + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002c910022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d0001029808000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102590a0a08000106307375313633393531373138353237327263333436663765383431383562656439353237313534643261343866343562391a0900010a0602414c1630737531363339353137313835323732726333343666376538343138356265643935323731353464326134386634356239261b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386003790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313633393531373138353237327263333436663765383431383562656439353237313534643261343866343562397c0b0b1900040a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701c2c30ff4a0105001102d00b56086e656564776d3d30680c7601320b2601303c46005c630000017dbad6e4f87c81074e9003a103e8b103e8c103e8d600e60861707069643d38310b0b160732353037373033260732353037373033325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "mlbb" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1057, + "superscriptType": 0, + "anchorCountryCode": "ID", + "fps": null, + "anchorAnnouncement": "Hi! I am a new streamer of Nimo. Hope you enjoy my livestream and feel free to tap that \"Follow\" button!", + "showScreenshots": null, + "follow": null, + "liveId": 0, + "microPKStatus": 0, + "userId": null, + "roomTheme": "EHH UPSSSS", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": null, + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 910, + "onlineStatus": 0, + "endLiveTime": 1598409073, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 6471220485, + "sharpness": null, + "roomType": 176, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/2399515571431/202007191595155595008_2399515571431_avatar.png", + "roomTypeName": "Just chatting", + "isLottery": 0, + "anchorId": 2399515571431, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "Español ", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Medusa", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su2399515571431r830b6cc9f9eaef649b00dc707866b584.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su2399515571431r830b6cc9f9eaef649b00dc707866b584_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su2399515571431r830b6cc9f9eaef649b00dc707866b584_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2399515571431r830b6cc9f9eaef649b00dc707866b584_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2399515571431r830b6cc9f9eaef649b00dc707866b584_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 2399515571431, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 6471220485, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002cf10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d0001029e08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001025f0a0a08000106307375323339393531353537313433317238333062366363396639656165663634396230306463373037383636623538341a0900010a060257531630737532333939353135353731343331723833306236636339663965616566363439623030646337303738363662353834261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce019f00f19f01019f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375323339393531353537313433317238333062366363396639656165663634396230306463373037383636623538347c0b0b1900040a0604373230701c2c30ff4a0105001102d00b56086e656564776d3d30680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b2601303c46005c630000022eae45f4e77c81082a9006a103e8b103e8c103e8d600e60861707069643d38310b0b160a36343731323230343835260a36343731323230343835325f461f9d0b8c980ca80c", + "gameAbbrList": null, + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1034, + "superscriptType": 0, + "anchorCountryCode": "AR", + "fps": null, + "anchorAnnouncement": "Hola chinchulinnnn estoy on♥ pasate", + "showScreenshots": null, + "follow": null, + "liveId": 6865114694762352955, + "microPKStatus": 0, + "userId": null, + "roomTheme": "que pasaaa padre", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "medusa", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 899, + "onlineStatus": 0, + "endLiveTime": 1598418607, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 39002863, + "sharpness": null, + "roomType": 30, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/201906081559988405517_1639513614298_avatar.png", + "roomTypeName": "我要活下去", + "isLottery": 0, + "anchorId": 1639513614298, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "Español ", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Ronsito IUTU", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su1639513614298r79cc5e7edf976aa9c25fd939beae180a.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639513614298r79cc5e7edf976aa9c25fd939beae180a_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1639513614298, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 39002863, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313633393531333631343239387237396363356537656466393736616139633235666439333962656165313830611a0900010a060254581630737531363339353133363134323938723739636335653765646639373661613963323566643933396265616531383061261b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386005790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f74782e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f74782e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313633393531333631343239387237396363356537656466393736616139633235666439333962656165313830617c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c630000017dbaa067da7c811a309006a103e8b103e8c103e8d600e60861707069643d38310b0b1608333930303238363326083339303032383633325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "freefire" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1034, + "superscriptType": 0, + "anchorCountryCode": "CO", + "fps": null, + "anchorAnnouncement": "bienvenidos \n\nINSTAGRAM: Ron_sito\nYOUTUBE: RonsitoIUTU\nDISCORD: https://discord.gg/ghy7fUf", + "showScreenshots": [ + { + "key": 1, + "url": "https://server-cover-prod.nimostatic.tv/201906181560900407307_1639513614298_cover.png?t=1598431320000" + }, + { + "key": 2, + "url": "https://server-cover-prod.nimostatic.tv/201906181560900407307_1639513614298_cover.png?t=1598431320000" + }, + { + "key": 3, + "url": "https://server-cover-prod.nimostatic.tv/201906181560900407261_1639513614298_cover.png?t=1598431320000" + } + ], + "follow": null, + "liveId": 6865155646921936842, + "microPKStatus": 0, + "userId": null, + "roomTheme": "HOLA BROS", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "ronsitoyt", + "businessType": 1 + }, + { + "authenticatedAnchor": 1, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 859, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 522143336, + "sharpness": null, + "roomType": 25, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/202004131586772912270_1639512602399_avatar.png", + "roomTypeName": "无尽对决", + "isLottery": 0, + "anchorId": 1639512602399, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 2, + "lcidText": "Bahasa Indonesia", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "BTR Branz", + "roomScreenshots": [ + { + "key": 1, + "url": "https://web-ops.nimostatic.tv/banner/E2A472075E780ACCEC4601D3B1531EF3_2cb7565636e89d2be91f1b4125395730.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://web-ops.nimostatic.tv/banner/CE9D4D905CC27E278CB3CDD5EBAEC040_f04d7dc22b192665f1b367a5504e20f7.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://web-ops.nimostatic.tv/banner/6CBF2F7FD12A6D63E79DB1E036B82DB0_5575db9aaa1d6648d67bd593ff973e64.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1639512602399r9fd08d553742320840a095333d5ec42d_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su1639512602399r9fd08d553742320840a095333d5ec42d_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 1639512602399, + "bIfLiveInter": true, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 522143336, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002cd10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d0001029c08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001025d0a0a08000106307375313633393531323630323339397239666430386435353337343233323038343061303935333333643565633432641a0900010a060257531630737531363339353132363032333939723966643038643535333734323332303834306130393533333364356563343264261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313633393531323630323339397239666430386435353337343233323038343061303935333333643565633432647c0b0b1900040a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701c2c30ff4a0105001102d00b56086e656564776d3d30680c7601320b2601303c46005c630000017dba90f71f7c8102f69001a103e8b103e8c103e8d600e60861707069643d38310b0b16093532323134333333362609353232313433333336325f4620630b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "mlbb" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1057, + "superscriptType": 0, + "anchorCountryCode": "ID", + "fps": null, + "anchorAnnouncement": "Mobile Legends player of Bigetron Esports\n\nIG: @btr_branz\nYT: Branz", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "JADI STREAMER AJA", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "branz", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 851, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 47348472, + "sharpness": null, + "roomType": 51, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/202004111586589853140_1599515507791_avatar.png", + "roomTypeName": "腐蚀", + "isLottery": 0, + "anchorId": 1599515507791, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 0, + "lcidText": "ไทย", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "GEUM", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599515507791r1ede01c67fe148793dd1fa50a7cfc0ce_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599515507791, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 47348472, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313539393531353530373739317231656465303163363766653134383739336464316661353061376366633063651a0900010a0602414c1630737531353939353135353037373931723165646530316336376665313438373933646431666135306137636663306365261b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386003790c8c9600a6062e736c696365bcccd90ce064f00f64f01064f61100f81200020603666c761a0603666c76161b687474703a2f2f616c2e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f616c2e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531353530373739317231656465303163363766653134383739336464316661353061376366633063657c0b0b1900050a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c63000001746a8dbc4f7c8117fb9003a103e8b103e8c103e8d600e60861707069643d38310b0b1608343733343834373226083437333438343732325f461f9d0b8c980ca80c", + "gameAbbrList": null, + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1054, + "superscriptType": 0, + "anchorCountryCode": "TH", + "fps": null, + "anchorAnnouncement": "\uD83C\uDF1F Facebook ➡ Jack jazper\n\nPC Spec \uD83D\uDDA5 สเปคคอม\n\uD83D\uDCA2 CPU : Intel i9 9900K\n\uD83D\uDCA2 MB : ASUS Z390-A \n\uD83D\uDCA2 Memory : G.skill tridentz RGB DDR4 32 GB\n\uD83D\uDCA2 SSD : SAMSUNG 960 EVO M.2 500 GB\n\uD83D\uDCA2 GPU : ASUS Geforce GTX 1080 TI OC\n\uD83D\uDCA2 Mornitor : Predator 240hz \" 24.5 \"", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "กึ่ม - รัชดา !!", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": null, + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": 1, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 850, + "onlineStatus": 0, + "endLiveTime": 1598420223, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 1, + "createdTime": null, + "id": 42248746, + "sharpness": null, + "roomType": 249, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/1599516503052/202007161594898924507_1599516503052_avatar.png", + "roomTypeName": "聯盟戰棋", + "isLottery": 0, + "anchorId": 1599516503052, + "version": null, + "fanCount": null, + "anchorLabels": [ + { + "timeStamp": 1598431322056, + "anchorLabelType": 2, + "labelId": 15, + "labelNameLang": "", + "sort": 130, + "labelName": "競猜", + "type": 1 + } + ], + "roomSort": 0, + "lcidText": "Tiếng Việt", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "TG Green", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su1599516503052rf4392203acda08a89be56b186da47b86.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su1599516503052rf4392203acda08a89be56b186da47b86_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su1599516503052rf4392203acda08a89be56b186da47b86_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_veryhigh/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_veryhigh.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_veryhigh.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_high.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_high.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_low.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_low.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + }, + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su1599516503052rf4392203acda08a89be56b186da47b86_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1920, + "lUid": 1599516503052, + "bIfLiveInter": false, + "iHeight": 1080, + "iBusinessType": 1, + "lRoomId": 42248746, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": "競猜", + "expireLabelIds": [], + "isDeleted": 0, + "bitRate": null, + "mStreamPkg": "000002f310022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102c208000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d000102830a0a08000106307375313539393531363530333035327266343339323230336163646130386138396265353662313836646134376238361a0900010a060257531630737531353939353136353033303532726634333932323033616364613038613839626535366231383664613437623836261b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f36042e666c76461b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f56052e6d3375386001790c8c9600a6062e736c696365bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161b687474703a2f2f77732e666c762e6e696d6f2e74762f6c6976652f26042e666c76390c4001506466007c0b0603686c731a0603686c73161b687474703a2f2f77732e686c732e6e696d6f2e74762f6c6976652f26052e6d337538390c40015c663369643d7375313539393531363530333035327266343339323230336163646130386138396265353662313836646134376238367c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701117702c30ff4a0107801104380b56086e656564776d3d31680c7601360b2601303c46005c63000001746a9cec0c7c811f249003a103e8b103e8c103e8d600e60861707069643d38310b0b1608343232343837343626083432323438373436325f461f9d0b8c980ca80c", + "gameAbbrList": null, + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1066, + "superscriptType": 3, + "anchorCountryCode": "VN", + "fps": null, + "anchorAnnouncement": "TG Green: Lịch live từ 12:30 - 16:30 Hằng ngày\n_____________\nDonate cho Green tại:\n057704060121100 VIB Nguyễn Đình Thành \nhttps://playerduo.com/tggreen\n https://qr.wescan.vn/tggreen\nMomo: 0983554641\n_____________\nGroup team: https://www.facebook.com/groups/DTCLToGaming/\nDiscord team: https://discord.gg/EMpsTaw\nFacebook cá nhân : https://www.facebook.com/l3ankl30\n#TG #ToGaming #DTCL #TFT #TGGreen", + "showScreenshots": null, + "follow": null, + "liveId": 6865162585380335040, + "microPKStatus": 0, + "userId": null, + "roomTheme": "TRY HARD RANK TĐ ĐTCL", + "anchorSex": 1, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "tggreen", + "businessType": 1 + }, + { + "authenticatedAnchor": 0, + "templateType": null, + "avatarBoxUrl": null, + "eventRoomListView": null, + "viewerNum": 843, + "onlineStatus": 0, + "endLiveTime": null, + "anchorScreenshots": null, + "backgroundImg": null, + "isGuessing": 0, + "createdTime": null, + "id": 5361637521, + "sharpness": null, + "roomType": 21, + "eventId": null, + "updatedTime": null, + "headImg": null, + "anchorAvatarUrl": "https://server-avatar.nimostatic.tv/2029517878589/202007111594466120366_2029517878589_avatar.png", + "roomTypeName": "PUBG Mobile", + "isLottery": 0, + "anchorId": 2029517878589, + "version": null, + "fanCount": null, + "anchorLabels": null, + "roomSort": 3, + "lcidText": "Türkçe", + "roomNumbering": null, + "teamRoomViews": null, + "description": null, + "title": null, + "viewerNumRef": null, + "anchorName": "Bahar Zünbül", + "roomScreenshots": [ + { + "key": 1, + "url": "https://txpic.vod.nimo.tv/su2029517878589re0a8173bb45d4974afc5db0d68cb043f.jpg?t=1598431320000" + }, + { + "key": 2, + "url": "https://txpic.vod.nimo.tv/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_338_190.jpg?t=1598431320000" + }, + { + "key": 3, + "url": "https://txpic.vod.nimo.tv/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_136_76.jpg?t=1598431320000" + } + ], + "platform": null, + "roomLineInfo": { + "vCodeLines": [], + "vCodeLines2": [ + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f/playlist.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f.flv?needwm=0" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f.m3u8?needwm=0" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 6000, + "iNameCode": 6 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_high/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_high.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_high.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_high.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 2000, + "iNameCode": 2 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_mid/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_mid.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_mid.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_mid.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 1000, + "iNameCode": 3 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_low/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_low.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_low.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_low.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 500, + "iNameCode": 4 + }, + { + "vCdns": [ + { + "iCdnType": 1, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://ws.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://ws.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_verylow/playlist.m3u8" + } + ], + "iCdnTypeHY": 1 + }, + { + "iCdnType": 2, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://tx.flv.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://tx.hls.nimo.tv/live/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_verylow.m3u8" + } + ], + "iCdnTypeHY": 5 + }, + { + "iCdnType": 3, + "vCdnUrls": [ + { + "imediaType": 1, + "smediaUrl": "http://al.flv.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_verylow.flv" + }, + { + "imediaType": 2, + "smediaUrl": "http://al.hls.nimo.tv/backsrc/su2029517878589re0a8173bb45d4974afc5db0d68cb043f_verylow.m3u8" + } + ], + "iCdnTypeHY": 3 + } + ], + "iBitRate": 250, + "iNameCode": 5 + } + ], + "iWidth": 1280, + "lUid": 2029517878589, + "bIfLiveInter": false, + "iHeight": 720, + "iBusinessType": 1, + "lRoomId": 5361637521, + "mLineInfo": {}, + "iRecommendCode": 3 + }, + "superscriptText": null, + "expireLabelIds": null, + "isDeleted": null, + "bitRate": null, + "mStreamPkg": "000002fb10022c3c4c56074d656469615549661367657453747265616d496e666f4279526f6f6d7d000102ca08000206001800010605696e7433321d0000010c060474527370180001061b485559412e47657453747265616d496e666f4279526f6f6d5273701d0001028b0a0a08000106307375323032393531373837383538397265306138313733626234356434393734616663356462306436386362303433661a0900010a0602414c1630737532303239353137383738353839726530613831373362623435643439373461666335646230643638636230343366261e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f36042e666c76461e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f56052e6d3375386003790c8c9600a600bcccd90ce032f00f32f01032f61100f81200020603666c761a0603666c76161e687474703a2f2f616c2e666c762e6e696d6f2e74762f6261636b7372632f26042e666c76390c4001506466007c0b0603686c731a0603686c73161e687474703a2f2f616c2e686c732e6e696d6f2e74762f6261636b7372632f26052e6d337538390c40015c663369643d7375323032393531373837383538397265306138313733626234356434393734616663356462306436386362303433667c0b0b1900050a0604323430701100fa2c30ff4a0101451100f00b56086e656564776d3d31680c7601350b0a0604333630701101f42c30ff4a0101e01101680b56086e656564776d3d31680c7601340b0a0604343830701103e82c30ff4a01035a1101e00b56086e656564776d3d31680c7601330b0a0604373230701109c42c30ff4a0105001102d00b56086e656564776d3d31680c7601320b0a060531303830701c2c30ff4a0107801104380b56086e656564776d3d30680c7601360b2601303c46005c63000001d888b1353d7c810a669001a103e8b103e8c103e8d600e60861707069643d38310b0b160a35333631363337353231260a35333631363337353231325f461fe30b8c980ca80c", + "gameAbbrList": [ + { + "langId": 1033, + "value": "pubgmobile" + } + ], + "nextLiveNoticeTimestamp": null, + "isPlayback": 0, + "starLiveRoomView": null, + "lcid": 1055, + "superscriptType": 0, + "anchorCountryCode": "TR", + "fps": null, + "anchorAnnouncement": "Herkese selamlar ben Bahar,\nGiderek büyüyen ‘’DNY’’ ailesine katılmak için doğru yerdesin.İyiliğe, güzelliğe dair her muhabbete eşlik edip, bizimle oyun oynayarak ödüller kazanabilirsin..\nHer gün sabah 10:00 ve akşam 18:00 de biz buradayız.\nSende iyi ki burdasın. \uD83C\uDF38\nDiscord \nhttps://discord.gg/dWZMTDS\nYoutube \nhttps://www.youtube.com/channel/UCmZDJEOtgDImfTAAf2OBjcQ?view_as=subscriber\nİnstagram\nbahar.zunbul", + "showScreenshots": null, + "follow": null, + "liveId": null, + "microPKStatus": 0, + "userId": null, + "roomTheme": "Yeni M24 Çarkı çeviriyoruz..", + "anchorSex": 2, + "coverLabels": null, + "liveStreamStatus": 1, + "viewerScore": null, + "teamId": null, + "alise": "baharzunbul", + "businessType": 1 + } + ], + "gameEntityList": [ + { + "gameId": 10, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"League of Legends\",\"langId\":1025},{\"value\":\"League of Legends\",\"langId\":1028},{\"value\":\"League of Legends\",\"langId\":1033},{\"value\":\"League of Legends\",\"langId\":1034},{\"value\":\"リーグオブレジェンド\",\"langId\":1041},{\"value\":\"League of Legends\",\"langId\":1046},{\"value\":\"League of Legends\",\"langId\":1049},{\"value\":\"League of Legends\",\"langId\":1054},{\"value\":\"League of Legends\",\"langId\":1055},{\"value\":\"League of Legends\",\"langId\":1057},{\"value\":\"Liên Minh Huyền Thoại\",\"langId\":1066},{\"value\":\"League of Legends\",\"langId\":1081},{\"value\":\"League of Legends\",\"langId\":1086},{\"value\":\"League of Legends\",\"langId\":1124}]", + "updateTime": null, + "type": 2, + "platform": 2, + "gameName": "League of Legends", + "liveOnNumber": null, + "pos": 1, + "name": "League of Legends", + "logo": "https://web-ops.nimostatic.tv/banner/8689359D3F5D4F06BFB28D78900287C_8689359D3F5D4F06BFB28D78900287C_lolX.jpg", + "gameAbbrList": [ + { + "langId": 1033, + "value": "lol" + } + ], + "id": 136, + "businessType": null + }, + { + "gameId": 32, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"爐石戰記\",\"langId\":1028},{\"value\":\"Hearthstone\",\"langId\":1033},{\"value\":\"Hearthstone\",\"langId\":1034},{\"value\":\"ハースストーン\",\"langId\":1041},{\"value\":\"Hearthstone\",\"langId\":1046},{\"value\":\"Hearthstone\",\"langId\":1054},{\"value\":\"Hearthstone\",\"langId\":1057},{\"value\":\"Hearthstone\",\"langId\":1066},{\"value\":\"Hearthstone\",\"langId\":1081},{\"value\":\"Hearthstone\",\"langId\":1086},{\"value\":\"Hearthstone\",\"langId\":1124}]", + "updateTime": null, + "type": 2, + "platform": 2, + "gameName": "爐石戰記", + "liveOnNumber": null, + "pos": 2, + "name": "爐石戰記", + "logo": "https://web-ops.nimostatic.tv/banner/95E85B748B7BF84FB25528A83697654A_95E85B748B7BF84FB25528A83697654A_Hearthstone.jpg", + "gameAbbrList": [ + { + "langId": 1033, + "value": "hearthstone" + } + ], + "id": 137, + "businessType": null + }, + { + "gameId": 208, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"في الهواء الطلق\",\"langId\":1025},{\"value\":\"户外\",\"langId\":1028},{\"value\":\"Outdoor\",\"langId\":1033},{\"value\":\"Al aire libre\",\"langId\":1034},{\"value\":\"Ao ar livre\",\"langId\":1046},{\"value\":\"на открытом воздухе\",\"langId\":1049},{\"value\":\"กลางแจ้ง\",\"langId\":1054},{\"value\":\"açık\",\"langId\":1055},{\"value\":\"Di luar\",\"langId\":1057},{\"value\":\"Ngoài trời\",\"langId\":1066},{\"value\":\"घर के बाहर\",\"langId\":1081},{\"value\":\"Luar\",\"langId\":1086},{\"value\":\"Panlabas\",\"langId\":1124}]", + "updateTime": null, + "type": 3, + "platform": 2, + "gameName": "户外", + "liveOnNumber": null, + "pos": 3, + "name": "户外", + "logo": "https://web-ops.nimostatic.tv/banner/BF155E297933B2B69E892F5953A94DE3_BF155E297933B2B69E892F5953A94DE3_huwai.png", + "gameAbbrList": null, + "id": 138, + "businessType": null + }, + { + "gameId": 209, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"لعبة المضيف\",\"langId\":1025},{\"value\":\"主機遊戲\",\"langId\":1028},{\"value\":\"Host game\",\"langId\":1033},{\"value\":\"Juego anfitrión\",\"langId\":1034},{\"value\":\"ホストゲーム\",\"langId\":1041},{\"value\":\"Jogo host\",\"langId\":1046},{\"value\":\"Хост игра\",\"langId\":1049},{\"value\":\"เกมโฮสต์\",\"langId\":1054},{\"value\":\"Ev sahibi oyunu\",\"langId\":1055},{\"value\":\"Game tuan rumah\",\"langId\":1057},{\"value\":\"Trò chơi máy chủ\",\"langId\":1066},{\"value\":\"मेजबान खेल\",\"langId\":1081},{\"value\":\"Permainan hos\",\"langId\":1086},{\"value\":\"Host game\",\"langId\":1124}]", + "updateTime": null, + "type": 2, + "platform": 2, + "gameName": "主機遊戲", + "liveOnNumber": null, + "pos": 4, + "name": "主機遊戲", + "logo": "https://web-ops.nimostatic.tv/banner/308806D3D62B1C53D4160E54B419BA90_308806D3D62B1C53D4160E54B419BA90_312468.png", + "gameAbbrList": null, + "id": 139, + "businessType": null + }, + { + "gameId": 210, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"جمال\",\"langId\":1025},{\"value\":\"顏值\",\"langId\":1028},{\"value\":\"Beauty\",\"langId\":1033},{\"value\":\"Belleza\",\"langId\":1034},{\"value\":\"Beleza\",\"langId\":1046},{\"value\":\"красота\",\"langId\":1049},{\"value\":\"ความงาม\",\"langId\":1054},{\"value\":\"Güzellik\",\"langId\":1055},{\"value\":\"Keindahan\",\"langId\":1057},{\"value\":\"sắc đẹp, vẻ đẹp\",\"langId\":1066},{\"value\":\"सुंदरता\",\"langId\":1081},{\"value\":\"Kecantikan\",\"langId\":1086},{\"value\":\"Kagandahan\",\"langId\":1124}]", + "updateTime": null, + "type": 3, + "platform": 2, + "gameName": "顏值", + "liveOnNumber": null, + "pos": 5, + "name": "顏值", + "logo": "https://web-ops.nimostatic.tv/banner/329B1500F7244A46A16FA977CC3840B2_329B1500F7244A46A16FA977CC3840B2_312468.png", + "gameAbbrList": null, + "id": 140, + "businessType": null + }, + { + "gameId": 169, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"Speed Drifters\",\"langId\":1025},{\"value\":\"極速領域\",\"langId\":1028},{\"value\":\"Speed Drifters\",\"langId\":1033},{\"value\":\"Speed Drifters\",\"langId\":1034},{\"value\":\"Speed Drifters\",\"langId\":1041},{\"value\":\"Speed Drifters\",\"langId\":1046},{\"value\":\"Speed Drifters\",\"langId\":1049},{\"value\":\"Speed Drifters\",\"langId\":1054},{\"value\":\"Speed Drifters\",\"langId\":1055},{\"value\":\"Speed Drifters\",\"langId\":1057},{\"value\":\"Speed Drifters\",\"langId\":1066},{\"value\":\"Speed Drifters\",\"langId\":1081},{\"value\":\"Speed Drifters\",\"langId\":1086},{\"value\":\"Speed Drifters\",\"langId\":1124}]", + "updateTime": null, + "type": 1, + "platform": 2, + "gameName": "極速領域", + "liveOnNumber": null, + "pos": 6, + "name": "極速領域", + "logo": "https://web-ops.nimostatic.tv/banner/958840DD11959FD5B111B4F950FCB1B2_123.webp", + "gameAbbrList": null, + "id": 141, + "businessType": null + }, + { + "gameId": 185, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"Liveshow\",\"langId\":1025},{\"value\":\"星秀\",\"langId\":1028},{\"value\":\"Liveshow\",\"langId\":1033},{\"value\":\"Lifestyle\",\"langId\":1034},{\"value\":\"エンタテイメント\",\"langId\":1041},{\"value\":\"Lifestyle\",\"langId\":1046},{\"value\":\"Прямая трансляция\",\"langId\":1049},{\"value\":\"Life Style\",\"langId\":1054},{\"value\":\"Show&Sohbet!\",\"langId\":1055},{\"value\":\"Live Show\",\"langId\":1057},{\"value\":\"The Nimo Show\",\"langId\":1066},{\"value\":\"Show Time\",\"langId\":1081},{\"value\":\"Liveshow\",\"langId\":1086},{\"value\":\"HOHOL\",\"langId\":1124}]", + "updateTime": null, + "type": 3, + "platform": 2, + "gameName": "星秀", + "liveOnNumber": null, + "pos": 7, + "name": "星秀", + "logo": "https://web-ops.nimostatic.tv/banner/C729D8401FDAC50C9F7A190133AC15D8_C729D8401FDAC50C9F7A190133AC15D8_312468.jpg", + "gameAbbrList": null, + "id": 142, + "businessType": null + }, + { + "gameId": 25, + "templateType": 1, + "clientId": 0, + "clientName": null, + "nameLang": "[{\"value\":\"Mobile Legends\",\"langId\":1025},{\"value\":\"无尽对决\",\"langId\":1028},{\"value\":\"Mobile Legends\",\"langId\":1033},{\"value\":\"Mobile Legends\",\"langId\":1034},{\"value\":\"モバイルレジェンド\",\"langId\":1041},{\"value\":\"Mobile Legends\",\"langId\":1046},{\"value\":\"Mobile Legends\",\"langId\":1049},{\"value\":\"Mobile Legends\",\"langId\":1054},{\"value\":\"Mobile Legends\",\"langId\":1055},{\"value\":\"Mobile Legends\",\"langId\":1057},{\"value\":\"Mobile Legends\",\"langId\":1066},{\"value\":\"Mobile Legends\",\"langId\":1081},{\"value\":\"Mobile Legends\",\"langId\":1086},{\"value\":\"Mobile Legends\",\"langId\":1124}]", + "updateTime": null, + "type": 1, + "platform": 2, + "gameName": "无尽对决", + "liveOnNumber": null, + "pos": 1, + "name": "无尽对决", + "logo": "https://web-ops.nimostatic.tv/banner/8057713FBF57F89AC21299AF3711720E_Mobilelegends.jpg", + "gameAbbrList": [ + { + "langId": 1033, + "value": "mlbb" + } + ], + "id": 16, + "businessType": null + } + ] + }, + "keyType": 0 + } +} \ No newline at end of file From a72ba6257c4bbe9543e29d58909afacd44b7b95d Mon Sep 17 00:00:00 2001 From: eson <474420502@qq.com> Date: Sun, 30 Aug 2020 05:31:15 +0800 Subject: [PATCH 03/18] change: gcurl version --- go.mod | 3 +-- go.sum | 20 ++------------------ 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 7848053..ca8b0a7 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,8 @@ go 1.15 require ( github.com/474420502/extractor v0.9.6 github.com/474420502/focus v0.12.0 - github.com/474420502/gcurl v0.4.4 + github.com/474420502/gcurl v0.4.5 github.com/474420502/requests v1.9.1 - github.com/davecgh/go-spew v1.1.1 github.com/go-sql-driver/mysql v1.5.0 github.com/lestrrat-go/libxml2 v0.0.0-20200215080510-6483566f52cb github.com/tebeka/selenium v0.9.9 diff --git a/go.sum b/go.sum index c7770c9..e1c4012 100644 --- a/go.sum +++ b/go.sum @@ -6,28 +6,14 @@ github.com/474420502/extractor v0.9.6 h1:mwwzwVeu/sZ4FV190Bl32ta4iVjERBWL6eGLXRD github.com/474420502/extractor v0.9.6/go.mod h1:vJnXWmvO5bJDW4Yag0GoE2GxtHRg03TAxp2oXN1DcSY= github.com/474420502/focus v0.12.0 h1:+icbmj7IEOefvTegHt5EpcHt6WFbe2miIrceUJx2Evo= github.com/474420502/focus v0.12.0/go.mod h1:d0PMjtMxFz1a9HIhwyFPkWa+JF+0LgOrEUfd8iZka6s= -github.com/474420502/gcurl v0.2.0 h1:m6+vw4NX4f5Tfp7c3nuaIgHUE/7zTX6K3xK+pTCBoCo= -github.com/474420502/gcurl v0.2.0/go.mod h1:kJZDbgXn5wbAaR+hhBi4Sbw44P4igJ7qYXC6mejLuhQ= -github.com/474420502/gcurl v0.3.0 h1:j0YP55ANQUHDF86pL5rCqfC+dX887uL9GxHFE3Zj31k= -github.com/474420502/gcurl v0.3.0/go.mod h1:kJZDbgXn5wbAaR+hhBi4Sbw44P4igJ7qYXC6mejLuhQ= -github.com/474420502/gcurl v0.4.0 h1:HOnuYhZD2rwvAXdrF1tqS6gQYYcpnpcPVdOVbDsFT4E= -github.com/474420502/gcurl v0.4.0/go.mod h1:kJZDbgXn5wbAaR+hhBi4Sbw44P4igJ7qYXC6mejLuhQ= -github.com/474420502/gcurl v0.4.1 h1:js/s+w1yBkpSU5vo3kXLQs5F+NMwbNWI23Bcx3LDnnQ= -github.com/474420502/gcurl v0.4.1/go.mod h1:IOyP4j8lUCJaHqODzRyeZQcrQy9DGDalLc3z1gVuiJ4= -github.com/474420502/gcurl v0.4.3 h1:CwyKPrv8mzSL+pa7mrYpuVNEC7rst6MdHx0Enn+7cUk= -github.com/474420502/gcurl v0.4.3/go.mod h1:IOyP4j8lUCJaHqODzRyeZQcrQy9DGDalLc3z1gVuiJ4= github.com/474420502/gcurl v0.4.4 h1:ZILu7RRjDBGHpTGmuWGKf1NZZbZsC7AHPlI8RHqs9As= github.com/474420502/gcurl v0.4.4/go.mod h1:7w4knyVJa1ia4I1xd0krG51fKLGwMmNn5sfG2zPWbqM= +github.com/474420502/gcurl v0.4.5 h1:4y+NbbBGRIWDpfe/iojdSUzlShcZmnkHV4T4etiWQsw= +github.com/474420502/gcurl v0.4.5/go.mod h1:7w4knyVJa1ia4I1xd0krG51fKLGwMmNn5sfG2zPWbqM= github.com/474420502/htmlquery v1.2.4-0.20200812072201-e871dd09247a h1:E1T6CYQKsUn7fMvNbeKfISjBLfOJjZX4KpWwStT20Kc= github.com/474420502/htmlquery v1.2.4-0.20200812072201-e871dd09247a/go.mod h1:AoSN890esHwNKecV0tCs+W0ele1xgFL1Jqk6UcrdxgU= github.com/474420502/requests v1.7.0 h1:oaBwVrxZ7yZ+hDOKwHm2NflYib2y1geIUxBxQ2U48mw= github.com/474420502/requests v1.7.0/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= -github.com/474420502/requests v1.8.1 h1:zR2PE97PY6qTfwCtUl7fJ2Sg7JEXcXZg2nxgxrOutFU= -github.com/474420502/requests v1.8.1/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= -github.com/474420502/requests v1.8.2 h1:DiNLp8IlHjZKgNJbzLcwt89YosWBfkmjEMNmUXxF+Hs= -github.com/474420502/requests v1.8.2/go.mod h1:SLXrQ5dL9c7dkIeKNUCBAjOIt3J9KFCS2RQjWJecNwo= -github.com/474420502/requests v1.9.0 h1:c/oj1G4pGulIzljZ0WqoF8dkOCWjfJLmoyH+DCVRGH8= -github.com/474420502/requests v1.9.0/go.mod h1:x2T9l+e40R6kxxMvNm+YSZ9D6BHAXUDak4kQElIPJ9A= github.com/474420502/requests v1.9.1 h1:gCDmBCW1ym8zOvKKBGjEG9wafMY7imYk2u28+Oy1WEc= github.com/474420502/requests v1.9.1/go.mod h1:x2T9l+e40R6kxxMvNm+YSZ9D6BHAXUDak4kQElIPJ9A= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -128,8 +114,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= From 3b7e8e94ea4d7f5fc9e1e93f7d0a48c69a6a91d7 Mon Sep 17 00:00:00 2001 From: eson Date: Wed, 2 Sep 2020 18:56:20 +0800 Subject: [PATCH 04/18] =?UTF-8?q?nimo=20=E6=8F=92=E4=BB=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20nimo=20=E6=95=B0=E6=8D=AE=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=8F=90=E5=8F=96=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crx/myblock.crx | Bin 75903 -> 75993 bytes crx/myblock.pem | 52 +- extractor/nimo_extractor/nimo_extractor.go | 9 + .../nimo_extractor/nimo_extractor_test.go | 88 + .../twitch_extractor/tiwtch_extractor.go | 2 +- store.go | 1 + supervisor_conf/nimo_task1.conf | 13 + tasks/nimo/nimo_task1/main.go | 5 + tasks/nimo/nimo_task1/nimo_task1.go | 2 +- testfile/nimolive.html | 2015 +++++++++++++++++ utils.go | 3 + 11 files changed, 2162 insertions(+), 28 deletions(-) create mode 100644 extractor/nimo_extractor/nimo_extractor.go create mode 100644 extractor/nimo_extractor/nimo_extractor_test.go create mode 100644 supervisor_conf/nimo_task1.conf create mode 100644 tasks/nimo/nimo_task1/main.go create mode 100644 testfile/nimolive.html diff --git a/crx/myblock.crx b/crx/myblock.crx index 6ee88c65bb208fc887b525118235a905a7b66f8f..f4d1096e06124a7fbfd86f92e80b1aefdd5feb62 100644 GIT binary patch delta 4717 zcmZWs2{=^U8=pJYXzWYYFc>8yWKGCc$k?|rcG=ftDTb^SlEH{rd05`k4=*1)K1wmC zXRp`ddofT@w`0JuGVVB-O=9fokn$9eUv*fxlQAk)c~~vQ7|`OFbPs8`w88xYc@g9o2%Hw;E)B+5=B%ii8ds*NI+S;?a;$!Iko`{Npu+dfG9z)aa$@N+bvw6R{ zgc9s?vZ`R`7-r|vu4*#{B^GJb*pdPCjaa(|stV4nW0Z*qmIO$^Ts%bw+z<}a*)k?wL*2hnJ$uiY%9$ej;-K}D~4$&zeLr>$PDBcaGs z3^7EKN%cl{N+AcXDA^XxH}y)55riEsHP_c=B{$EI<27DiZIIfyqj#j6ln^*LVJ5z|r7Fm$^= zrB-y-O5CP&VB070fNKyDGk`$kNw~e~F4-RKbsz6@06Ax7mVoPk*gv4c0a# zD0ttlG;LZkM)k(10&Mr3R+r(A{vYNM-OE$~c|VwW8fiH)`p-SeXi4h*tS*qX;VVJ* zDw0@~O@>|1>tm&guqM>aW{C%xn;qoef@1O#NE%a4I4I`W3TqJ4RBLLxJ1>%4;uZeo zqQ&LIb;jK3;>)miKmYN0%f6FWAM9A7I(Vjch>4h;)(u95l}%^JL&=k11uD!*ZS--{ z8vW;2GF68S5MEKq#P4Q{!2>_O_ePxa>QsAeUVB}6%dqiUZ)L)0oKagI8pp^H8I2mL zP7e-$c@SMM+Lo*TNuZ!;Lv8cPaMFhwJ*Gtej2&}N{nk;Qgg){+c?Nz9r>+Ek$S%IChD3f^a;jbRn)BN=;yoEmaWZw@uk%$F+3Gn0D_~aSB;$7wr>vWsjP|KAizJ%`SQ20)^nYYRe~-~loyEvj(EO8+4vT@ zLz{)#x{?`5NT6e=s^M-waIS`6pShgAtzPOiKWB);eTnsD>kRQ~n@XF5^sNd+Do)&G zotf#yPvD&P0}`r5O+D%cxqww6@l|0(HxrMtl%=~@CYI)1r84R3{E?!M?0YR^Jr|q9 zY{e1iyxQ}V8h(4uRZoas?;lK}!tA}@kmuUU>DH5i2LdOudIFY{Ii=6B`hi!vv_*MG zRnF9kwa1U+ywbQkUZhbwa^xhA(aUx$@fTT?TPtllm5HdL*J;W{%cUm~ujM)0x+P(Y zPd6~W9+Ae;=nCAYLH-vN@iXh*!A}+dS0;xHrg-7wi?nrR^PQ{w@^+KlM{t&6M*&<{@^us9dHS1uG2(nCHSD#p)cI8}sY#AOS&|@uu=?jm^e*lE#D;-U0#3IGN~kJ#7RBU&KW=w%{FRI4eimsaYm9S~s9uKG=t9eI()gu2$&r1#)@af~v zp|^{(HTPGUo{)6WKP9WaSf-Uw60{(*Wet-Qjh!K} zNjDDtA~}~t?(-Ho3Gdo4<~I&1cBriOr&T^&zwrvvXL)T}MeTV!%1qDcx=TKZ?t=x7 zXOl6E)7=rM_kyD#g6{gyYf{W>vLrK=U`^+UI%0Ffc&If)us%hS@0(QXi_})JD3}p^ zn319J8~1T^c5ZoZkLl2i363B4T$_{`ku3wYc=rLBV`iW^5T$;MyLy;4VG|o+x6*DPH|LLaePkWNc`ivh2>UoC z)lK|3$qgBdvuBl4-m0*q&89fd-8+;x-D}(MT$rlE!_(aT#tUtE1sx=+O)a__{s1@g zy;t7W#en{b-{9))3S2^}1l_oTy;|kB2IxkB)Wz-PN1anM#i;Oe%5_cASNL_wSRCBU z!Tr4ort&v@zh>+wy*JgiT$$c@ou{l6F8lcnv7-e=9%^u!SOEJ zaNDhNO)9@wdaXNTBbHL%s1aRiN*fG!5*Y-22ZAD>X*b=EKHfB_9I-fcKH(sI1B1}x zXSgAi@jN=LY<^bd00=}}Nlu{zpd#Yp8d>e~amkgoj;j?__hgbvlBG4OdxTewuJgnY2GeNL+QV?-y3ulr;N5vfnQe+< z|8U{PHj+jqN#raTnFTHN080Cw8P$auEq4nd+5~@5BWHDyv(t?$v`4;&pi}Wy4pBZM zJ|U7yN1AFdLExsRCM5`BEItGcx{&P>fosOu1PK%5?39!QfeB{IMGykjLKp}FfY7lc z2nMa01iR=T9ocksc!HY${Jgl27zFa927wqrnCtui6S^Hoi|VRzBECA9spWk+4lyZ5 z6+sJcNND#{al2WfkL^co^u+&6U|^H4k~pi!6DfvuZ}Ru+fXtex^3QvE`}leI(TGGN zA3F%;O3sxcjF}z3H6%MiyEo)+%Bz13ql@_9#VDK4X!TN!lbV_wxLE_vk?t4s(qR5* zx925==u%#$N6Byv#r|a5dzpB9*}U#n)C*DC1^$?#&$zMD0U_h5!q_vSZ40W;)L6Y4 zpClmZ?s$cyf6lj%j3i41qJlXo!L?P?!v|RTx1nohGFm45j=GP7nUy8wi%{vc1Bs?^rp1!Bw5UBI#nkbJ#5XkJsLv zrlol#XA~Fjs1{{^6l&K}UciWiSe3S@m(Yo#Z}HAAJ3LjV>?$k?S6(s!my=Q^ioz2; zZ91yGq7Q+{X9Lb28)5CHALiK~zQ9EpbQkZ8+_y!kkB%kpcI|gK5WoN8ApX$hXJRzU zaZI^|Oa7r*4{ccfS%LknSNG?A^zP>ER*ooMm}!StP{7X0g}P!lnU>LvRpasvyq%qp zhyL6f?FJL@cUj~+OZ)A`h_60_YaMh`@X)FHs{Ce!Lus|B!W|E$?M&mVc3LTm9~t@b zgJW^1{OAppfdW7@%(DCQPd6FO7^In1kYGDk#?*d8u}i^vz^Bl*sIc$VmlP8IF|4T` zx?zgIN*Jmn+fNE9Xh7$8cfnU37$CFEGjlhpY$K!I)&jG8U!A?=S3&|kn zOLs&DeS&IooPRBb*W=u4?wUtiI>gF#@O0~^=Y9w%X1mG0y8QT^!z51Co~nkPV@XA5kK;?AslL7HTTt$>oFin>A}y3<0%wioU6(&Usu58+)6;hOY|?wIjgb)>xWBW2p^sHlwYtX4{0kAgH+ zsVn(x;!UfD{JyC)CafZLDI2{FR1e~ukwLyC2BssbGX0*`3ULyU1X}&to|WJ^YL`qD zxtO|z1lpyWOZrtA)7r-R5>7jb$eO#ZElh&Q+h;B0O*}(rj%Jj;L&>Lp4a>}p%c~TZ zgA9$WEG~ZNzbCnk4bE^uw|5Hy3FyskUQ{^xZ6`<>E~YZH$%4rcqb%U1X$ve|>1tuZbv`R&ry!|HjNAL0^{ z7h=4*Wh$PIpUYa>st+y~9bQ}bIoo>u6zRcxjzWD*@gGYD_+FXtK9Gn&Sq!~OzlqOe zXy-R4YLAos=0uZ8s^5&~v~-8Sc(sFMKp27YYR%Yz90D9e#0^|Nv4pwG4TzlnyTN#I z1H$L=bAJlNNtrm|!M|G=rkNXn{s#p48w0At06YLY!3!4;zy>T}yPL3+H(Ub%6Wss)E5i^>m0`;8rp})#Ta^DcHG%np_s?~* z632{R(k6Jz0eBF{pCEtxt388h;Rcv6vQU7Lu%61SqMcB@$2n3Ei1`#$1LF<__zCt# z$1_AGNbu#876f8B1tOwFU#4fn^g)5Mgq2T20X8rrGhWFoY~%g!)tpK(zS{iNVlaxl z0Ox;FO!XH81Zu%&($NY0L{(;&5|CpT*KeoU~@%@=M!;itA zP0%z5223>HpJ-E0l#lA=O#Sbz z;c+r&Fpi0V0X&4nRqU9=N^yZeck%u72DZn1#9JhQTz5uC4Dhp$@%=QY4?`mWKnc;Z c80IM7#c!Zod_N5`V#VkQ0Q{tfoF{qs9~sB`&;S4c delta 4670 zcmZu!1z40@^WUPETym+ULA;ctAW{Mnm+p0?yBidjMnMo*VCfK)4nZj;rAq-Rg^M5( zqO^eIx2%5OU+?oj&wHMC&YYRwoHOU0ne)z!LeAep60e}gn01sjwtVNV#o69Yv}LL^=HO%ohNy( z$jybTT2mx|CA8i=A=?g3i@MVgz108XcIGk{s&WyuKB;np#w{nvxNM-Ar6ThgDlw!%CT|UXok=QQ`?|&mW{j z^S)P>Io%;!@w}BY>W{GG3b|!$Qp43rJKuZ{Y0NY_Juqig~tl1N7Ta5i>V+m5CEhJ1!a#@f8i*Pux=8Y zy|;6qcFo}BERd5Z50&P4Ntncz(&a`_7N)^P6(Aq$fM6QiFI{gHRmi{?0v`;K04%-b zEWPc*-ra1rcrqzbznZDh-;kX+yW5)AkEXuaWm;2^(lH;yeixP=}b_! z&wqxlHj#HKg&!U5Q{$c4Zqd<(mPvFlY99{KOw2NJW zw^8Y&QLVQ!@)&_0#Jm15vHpxnZf=cbd_zOwVGuhOs4bI~R(g!iSb#8=wagi#{5{65 z-&CDZV&rrGk6gMYNm8J+FQ$Q zC^s(et}K8Bi}&|OACCr?D;bGLv0Z9wBCZbVEx!5iP{*>@!K=&Y?Lk&_1n)6akNGN; zZz;tg0-3Hh)H7oCO5;Jxmr!!s#A7WjqEK$x0~%$R{qPn*|ilar)RX#!aje2hkA4l;%et55ri{_ zULzegG>8~K4fXXmZS2;4EbOf3&1W6EQzze@a+kZJE9ldtgOKB*>ShM()TZc5&LfTw z7ba6Pjm_-F*++ycD~IZR;6_1t&z{R^v|{XTHqsSQXpV6`-8xqWMow)Mq4i5dTx(_r4VqWhY7bZ1*Vib=23Rzcw`xhP!A)8ai*cHX!+Y}k zHr<@pQ{x5J$macKR}oo9ygLMJ3EJlLv{0V&4s(HJMlE{d{Fj0G>RfK<;LS?$e7A|l z^4)7=lN8@J`VJnhbUWK>b?*DScVw^we7*|STrbRQ)`?qP@UOB80Fn-dpMI`T?-_Sf zL=m0ZLZ@^zFY&(Q6L}rDay`aY+B9j^|3e#Wdv8i49$b97^Deq@-@zf@Qjl?CXbK~J;piO7JwE1%dDQIfiG_9tEbE?Yn@fB zioRDZclEc$oy8rHT3DKs`A1v*IQ12MsyBSqScXV(s(dM)%Qy77gWxsNX`ChE&nI$?1AKM3X_~2-SE^zq%ovN===|IuP(H!>e;v@JRkD7oJ(-{AgHB46`;X z+Fp{wR_wzKTOA{eKXq-_UuB3v8}*`_#n&ub!zxts?JFt&CN;L>vaFjVk`fVAYsWDX z(j84D!t3MinDNEBsg6s=g#`9JUNP)9@8aTMwbUBhYAmwiC|n8Ael4o~mp{T;nz!r* zr6GB*;fvL7VFpmw)z9VpPGUJlgldsirx=U&=YLl(5Soo`IwpD;G@2I;^y{9LH~ z<;)OqfObfmi|kZ1tzm2+@Pm`luK%F@c(3qYyh@>m=@GK){o$HgXs5Z$Rx*pqF2!88K#aQS1ah_bl73KW zL~Pu2p@mMN!B|5hpmKQkmT!tclPLCN4&{yLX2?|tWfp8rB0tYGsR5h(lh5nQDpP;Y z)6^DkPHWrPhPSA#YDTLOaP{6|My(es{W#lm;K>|`oQ z$_knW#JE2SB1tQSnQY%*A#dP`B?xw;3p|OYlaQKoY^8Tch4$EAeH2!9*%S>iT!3vM zZ~d6ls?V9}E?^XLpZY+xf}zw+nUXrZTeBQRNqn;MOo!NFB62Sm_5o9o=-tv8IobYo z%=L6Gso@$6UC`c;P4&TmB9s$(Ta^h`8nGwdAQZOBpl;r(5U|evBYM#Mk!A6czkI-6 zOy-oGKE0096{oieEs5dC+dq1BLH z?G=ALbJ_SY@+%Id$um)>u?~|@uKuvTU7MChHooZezNUM*OEKx2z8YcbEWzL*z=u8u z`;pXSk<{eV#WVGZl+`mTp;1WO4#k87p|gY%QmiL6aaCX`!x^>IDc-SivX>@q`bPAD)9*XTA(3%sj@x zSp+XKN1Zwg85y21=CeiMi59gmT0EhM)U(4AsU7(cumDa;x~GWzGOi*oFcw^VQ4GM zgAL`S9GI3w5;Xgel9GaQF=|wky0Uvu^(2REowM?c_KKUzj~u>!HK!ci&Kk2SYrYqp zT6=w;7JwYyJt`?#;E)(Hd$H0O zvc1T};lL}Qu(x(r=V|+jis-Wj5&uZSGm8yr@f zyvz6Mn?!+!35?VQtkH&EViObX9~|_3OK3OFyeU#V@q&S&AC^*DCDa7Eou(ucxhI@7 z0v}VImh+pSvo&vGBIuQm$g&m7pelQgHrq*&EFv+}OkI`e++sQzZ?dU0c^4j8fe;kq zGS*+AU*vtfGdR^=V`9l|@*w>t4~@6)bG4$VrA8Ny(V#SiiVh_^sG;4gsaGY7&E|rL zelYn)PNHdfMz(U|IO8*oCcm@bM^F-3_9XeHM!9QIpTF+y(dvH<5Id^0g8?HB(Zuee zYE)0f@|RZLY$Q!-j~0x*K@mL(g-P8N$QIdx)|0=s$k#D`>wNq*mW5r4csc47>{ER~ zqB8aJo81Q%O_S>-AL4jk6%e-gIT@hCj(ozXOjZ^yFDX8A9mo_P&Jonm2eQT+FwMsm z8G)^dJ5qWN=6uuPE%luzdiNFOThO}!7Bhx(-=7jiQIl-Cn1%ActaNoLk9po0?NSjd zGTdkpnx@*fHpAokmLJ|J+}<7I*iS)y#{=B?ZE9*MFc3*}_*HBm-mOWwYSp;dTLrejtz+1liaMQ90JJGB~2I2mfDvxcL^)!woM z#okCMmDA4pZZ4H9Jv~a7G};&+Kg8n7cXcGr{HyF(%=40=hrvMe@p%uG$u3W_q=+JO z(35+n=KY2PPp<~u2S5sv1IRLXhvtP|q0d zQfot!qgEW{DKVcHz}H=~$7p%_FYdzxGBUY9#0`rke0BI)W5okjSWoi?qBBT-_D;`HUNMe@U!9S3$E>g zv2Sqzc;pKtpdXf$3kbLPqYRP#TPvRk0C07(7RDK~cXAMN_W9l5g;SmKPGrn*$vYUQ z%KFnD;HSX=68v^jxqx(dqm^8^J(5viJYfv~56<-aJmC)nxJpP305JW5^O_2$!i>Gd z{mU&f+&G*G`U@Pa8#j;=501t$f!f$CZXnx5LBhVe7~jQCa|2n~alZTQECB$Vh2L5k zmX-&IaJdlrzjOV!P$TyrUY8UX@^p9j-4z$=ZoAV{M!2Jh#q~dJu;2Jy9qYvhg#BC< zkA(}j9RMJQ>omWu2>>X>j`9FGP#3UF#!pmyaUOn(>wm%?wEhk&EGqf$RpF|vu5F=$ zjRy|98rR{!Z2UZ+Osp<1Pyq2q38ut 0 { + if do == nil { + return true, nil + } + if do(elements...) { + return true, nil + } + } + return false, nil + + }, time.Second*15) +} + +type LiveInfo struct { + Followers int64 `exp:"//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2']" mth:"r:ExtractNumber"` + Views int64 `exp:"//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']" mth:"r:ExtractNumber"` + Giver []int64 `exp:"//div[contains(@class,'rank-item-after3')]//span[contains(@class,'nimo-currency__count')]"` +} + +func Execute() { + wd := intimate.GetChromeDriver(3031) + waitfor := NewWaitFor(wd) + ps := intimate.NewPerfectShutdown() + + for !ps.IsClose() { + // streamer, err := estore.Pop(intimate.PNimo) + // if err != nil { + // log.Println(err) + // // estore.UpdateError(streamer, err) + // continue + // } + // log.Println(streamer) + var pagesource string + // wd.Get(streamer.LiveUrl.String) + wd.Get("https://www.nimo.tv/live/1253835677") + + waitfor.Default("//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2' and text() != '']", nil) + waitfor.Default("//div[contains(@class,'rank-item-top3')]", nil) + element, err := wd.FindElement(selenium.ByXPATH, "//div[contains(@class,'rank-item-top3')]") + if err != nil { + log.Println(err) + } else { + err = element.MoveTo(50, 50) + element.Click() + if err != nil { + log.Println(err) + } + } + + waitfor.Default("//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']", nil) + pagesource, _ = wd.PageSource() + etor := extractor.ExtractHtmlString(pagesource) + li := etor.GetObjectByTag(LiveInfo{}).(*LiveInfo) + log.Printf("%#v", li) + } +} diff --git a/extractor/twitch_extractor/tiwtch_extractor.go b/extractor/twitch_extractor/tiwtch_extractor.go index c6173ba..2ae0c23 100644 --- a/extractor/twitch_extractor/tiwtch_extractor.go +++ b/extractor/twitch_extractor/tiwtch_extractor.go @@ -29,7 +29,7 @@ func main() { // var err error for !ps.IsClose() { - streamer, err := estore.PopNoWait(intimate.Ptwitch, "tags is NULL", 15) + streamer, err := estore.Pop(intimate.Ptwitch) if streamer == nil || err != nil { if err != lasterr { log.Println(err, lasterr) diff --git a/store.go b/store.go index d49df1e..673bb81 100644 --- a/store.go +++ b/store.go @@ -228,6 +228,7 @@ func NewStoreExtractor() *StoreExtractor { return &StoreExtractor{db: db} } +// PopNoWait 弹出一个不用按时间间隔更新的主播信息, 主要用来测试. func (store *StoreExtractor) PopNoWait(platform Platform, condition string, operators ...int32) (*Streamer, error) { tx, err := store.db.Begin() if err != nil { diff --git a/supervisor_conf/nimo_task1.conf b/supervisor_conf/nimo_task1.conf new file mode 100644 index 0000000..778f858 --- /dev/null +++ b/supervisor_conf/nimo_task1.conf @@ -0,0 +1,13 @@ +[supervisord] +nodaemon=false + +[program:nimo_task1] +environment=DISPLAY=":99" +directory = MYPATH/bin/nimo_task1/ +command= MYPATH/bin/nimo_task1/nimo_task1 +# process_name=%(program_name)s_%(process_num)02d ;多进程名称 +# numprocs=1 ;启动多个进程 +autorestart=true +stderr_logfile=MYPATH/bin/nimo_task1/log +stderr_logfile_maxbytes=0 +stopsignal=QUIT diff --git a/tasks/nimo/nimo_task1/main.go b/tasks/nimo/nimo_task1/main.go new file mode 100644 index 0000000..736ef31 --- /dev/null +++ b/tasks/nimo/nimo_task1/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + Execute() +} diff --git a/tasks/nimo/nimo_task1/nimo_task1.go b/tasks/nimo/nimo_task1/nimo_task1.go index d423e90..827e0bf 100644 --- a/tasks/nimo/nimo_task1/nimo_task1.go +++ b/tasks/nimo/nimo_task1/nimo_task1.go @@ -59,7 +59,7 @@ func Execute() { log.Println(tp.GetURLRawPath(), "rooms:", len(rooms)) if len(rooms) == 0 { param.IntSet(1) - time.Sleep(time.Minute * 10) + time.Sleep(time.Minute * 15) continue } diff --git a/testfile/nimolive.html b/testfile/nimolive.html new file mode 100644 index 0000000..b91e763 --- /dev/null +++ b/testfile/nimolive.html @@ -0,0 +1,2015 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Best Allain VN 直播-AOV 直播-遊戲直播在線觀看 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
+
+
+
+ + Best Allain VN + + +
+
+
+
+
+

kéo rank nha các + bạn iew

+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + Nimo TV + +
12
+
+

Best Allain VN

+ +
-
+
followers:211 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • 480P
  • +
  • 360P
  • +
+
480P
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

您的瀏覽器不支持視頻自動播放

點擊播放 +
+
+
+
+ + Nimo TV + + +
+
+
+ kéo rank nha các bạn iew
+
+
+
+
Best Allain VN
+
+ +
-
+
+ followers:211
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + Nimo TV + +
+
+
+
+
+
+
+
+
+
+
+
+ + + 幸运草 + +
+
+
+
+ + + 咖啡 + +
+
+
+
+ + + 粉絲票 + +
+
+
+
+ + + 禮盒 + + + + Nimo TV + +
+
+
+
+ + + 彩蛋 + + + + Nimo TV + +
+
+
+
+ + + Carriage + + + + Nimo TV + +
+
+
+
+ + + 跑车 + + + + Nimo TV + +
+
+
+
+ + + 火箭 + + + + Nimo TV + +
+
+
+
+ + + Vietnam is the best + +
+
+
+
+ + + Romantic Skywheel + +
+
+
+
+ + + 丘比特 + +
+
+
+
+ + + 撒錢 + +
+
+
+
+ + + 旋轉木馬 + + + + Nimo TV + +
+
+
+
+ + + 摩托车 + +
+
+
+
+ + + 血瓶 + +
+
+
+
+ + + 炸彈 + +
+
+
+
+ + + 螢光棒 + +
+
+
+
+ + + 口罩 + +
+
+
+
+ + + 魔法書 + +
+
+
+
+
+
+
+
+
+
+
0 +
+
0 +
+
0 +
+
+
+
+
+
+
+
+
+
+
+ 貢獻榜
+
+ 貴賓席 (0)
+
+
粉絲榜
+
+
+
+
+
+ 我的王座還空著,快去收集禮物吧~
+
+
+
+
該主播未創建粉絲團
+
+
+
+
+
+
+
+
+
+
+
+ + 系統消息:Nimo官方提倡綠色直播,對直播內容進行24小時線上巡查。任何傳播違法、違規、低俗、暴力等不當訊息的行為將被停用帳號。請勿與他人私下交易轉帳,以免上當受騙。 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
    + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
  • +
  • +
  • +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+ +
    + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
  • +
  • +
  • +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+ +
    + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
  • + +
  • +
  • +
  • +
  • +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + +
+
+ +

+ 升級一下你的瀏覽器吧,使用體驗會很棒喲!

+
+
+
+
Chrome
+ 下載 +
+
+
+
Firefox
+ 下載 +
+
+
+
+ + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/utils.go b/utils.go index 2ed1a79..c3b9ac1 100644 --- a/utils.go +++ b/utils.go @@ -87,9 +87,12 @@ func GetChromeDriver(port int) selenium.WebDriver { caps := selenium.Capabilities{"browserName": "chrome"} chromecaps := chrome.Capabilities{} + + // chromecaps.AddExtension("/home/eson/test/myblock.crx") for _, epath := range []string{"../../../crx/myblock.crx", "../../crx/myblock.crx"} { _, err := os.Stat(epath) if err == nil { + err := chromecaps.AddExtension(epath) if err != nil { panic(err) From 5912111f290948e6e964420ff83ae7bc541cedbb Mon Sep 17 00:00:00 2001 From: eson Date: Wed, 2 Sep 2020 19:18:44 +0800 Subject: [PATCH 05/18] add: WaitFor method add: Channel tag --- .../nimo_extractor/nimo_extractor_test.go | 35 ++----------------- utils.go | 29 +++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/extractor/nimo_extractor/nimo_extractor_test.go b/extractor/nimo_extractor/nimo_extractor_test.go index 61bc2fb..bec1c67 100644 --- a/extractor/nimo_extractor/nimo_extractor_test.go +++ b/extractor/nimo_extractor/nimo_extractor_test.go @@ -4,7 +4,6 @@ import ( "intimate" "log" "testing" - "time" "github.com/474420502/extractor" "github.com/tebeka/selenium" @@ -14,44 +13,16 @@ func TestMain(t *testing.T) { Execute() } -type WaitFor struct { - WebDriver selenium.WebDriver -} - -func NewWaitFor(wd selenium.WebDriver) *WaitFor { - return &WaitFor{WebDriver: wd} -} - -func (wf *WaitFor) Default(xpath string, do func(elements ...selenium.WebElement) bool) error { - return wf.WebDriver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { - elements, err := wd.FindElements(selenium.ByXPATH, xpath) - if err != nil { - log.Println(err) - return false, err - } - - if len(elements) > 0 { - if do == nil { - return true, nil - } - if do(elements...) { - return true, nil - } - } - return false, nil - - }, time.Second*15) -} - type LiveInfo struct { Followers int64 `exp:"//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2']" mth:"r:ExtractNumber"` Views int64 `exp:"//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']" mth:"r:ExtractNumber"` + Channel string `exp:"//div[contains(@class,'nimo-rm_type')]//span"` Giver []int64 `exp:"//div[contains(@class,'rank-item-after3')]//span[contains(@class,'nimo-currency__count')]"` } func Execute() { wd := intimate.GetChromeDriver(3031) - waitfor := NewWaitFor(wd) + waitfor := intimate.NewWaitFor(wd) ps := intimate.NewPerfectShutdown() for !ps.IsClose() { @@ -78,8 +49,8 @@ func Execute() { log.Println(err) } } - waitfor.Default("//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']", nil) + pagesource, _ = wd.PageSource() etor := extractor.ExtractHtmlString(pagesource) li := etor.GetObjectByTag(LiveInfo{}).(*LiveInfo) diff --git a/utils.go b/utils.go index c3b9ac1..ee6a7d5 100644 --- a/utils.go +++ b/utils.go @@ -261,3 +261,32 @@ func (c *Counter) Add(n int) error { } return nil } + +type WaitFor struct { + WebDriver selenium.WebDriver +} + +func NewWaitFor(wd selenium.WebDriver) *WaitFor { + return &WaitFor{WebDriver: wd} +} + +func (wf *WaitFor) Default(xpath string, do func(elements ...selenium.WebElement) bool) error { + return wf.WebDriver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { + elements, err := wd.FindElements(selenium.ByXPATH, xpath) + if err != nil { + log.Println(err) + return false, err + } + + if len(elements) > 0 { + if do == nil { + return true, nil + } + if do(elements...) { + return true, nil + } + } + return false, nil + + }, time.Second*15) +} From be47c77e88f88c723c13ad837dedcab5e7708795 Mon Sep 17 00:00:00 2001 From: eson Date: Thu, 3 Sep 2020 12:01:55 +0800 Subject: [PATCH 06/18] TODO: upgrade store method --- .../nimo_extractor/nimo_extractor_test.go | 61 +++++++++++++------ utils.go | 6 +- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/extractor/nimo_extractor/nimo_extractor_test.go b/extractor/nimo_extractor/nimo_extractor_test.go index bec1c67..5491776 100644 --- a/extractor/nimo_extractor/nimo_extractor_test.go +++ b/extractor/nimo_extractor/nimo_extractor_test.go @@ -1,9 +1,11 @@ package main import ( + "database/sql" "intimate" "log" "testing" + "time" "github.com/474420502/extractor" "github.com/tebeka/selenium" @@ -17,7 +19,7 @@ type LiveInfo struct { Followers int64 `exp:"//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2']" mth:"r:ExtractNumber"` Views int64 `exp:"//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']" mth:"r:ExtractNumber"` Channel string `exp:"//div[contains(@class,'nimo-rm_type')]//span"` - Giver []int64 `exp:"//div[contains(@class,'rank-item-after3')]//span[contains(@class,'nimo-currency__count')]"` + Gratuity []int64 `exp:"//div[contains(@class,'rank-item-after3')]//span[contains(@class,'nimo-currency__count')]"` } func Execute() { @@ -26,34 +28,59 @@ func Execute() { ps := intimate.NewPerfectShutdown() for !ps.IsClose() { - // streamer, err := estore.Pop(intimate.PNimo) - // if err != nil { - // log.Println(err) - // // estore.UpdateError(streamer, err) - // continue - // } - // log.Println(streamer) - var pagesource string - // wd.Get(streamer.LiveUrl.String) - wd.Get("https://www.nimo.tv/live/1253835677") - - waitfor.Default("//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2' and text() != '']", nil) - waitfor.Default("//div[contains(@class,'rank-item-top3')]", nil) - element, err := wd.FindElement(selenium.ByXPATH, "//div[contains(@class,'rank-item-top3')]") + streamer, err := estore.Pop(intimate.PNimo) if err != nil { log.Println(err) + estore.UpdateError(streamer, err) + continue + } + + wd.Get(streamer.LiveUrl.String) + // wd.Get("https://www.nimo.tv/live/1253835677") + + waitfor.Default("//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2' and text() != '']", nil) + waitfor.WaitWithTimeout("//div[contains(@class,'rank-item-top3')]", 7*time.Second, nil) + element, err := wd.FindElement(selenium.ByXPATH, "//div[contains(@class,'rank-item-top3')]") + if err != nil { + log.Println(streamer.Uid, err) } else { err = element.MoveTo(50, 50) element.Click() if err != nil { - log.Println(err) + log.Println(streamer.Uid, err) } } waitfor.Default("//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']", nil) + var pagesource string pagesource, _ = wd.PageSource() + etor := extractor.ExtractHtmlString(pagesource) li := etor.GetObjectByTag(LiveInfo{}).(*LiveInfo) - log.Printf("%#v", li) + // log.Printf("%#v", li) + + utime := sql.NullTime{Time: time.Now(), Valid: true} + + clog := &intimate.CollectLog{} + clog.Platform = intimate.PNimo + clog.Followers = sql.NullInt64{Int64: li.Followers, Valid: true} + clog.Views = sql.NullInt64{Int64: li.Views, Valid: true} + clog.UpdateTime = utime + clog.StreamerUid = streamer.Uid + + var sum int64 = 0 + for _, v := range li.Gratuity { + sum += v + } + clog.Gratuity = sql.NullInt64{Int64: sum, Valid: true} + + cuid := estore.InsertClog(clog) + + streamer.Channel = sql.NullString{String: li.Channel, Valid: true} + streamer.LatestLogUid = cuid + streamer.UpdateTime = utime + streamer.Operator = 0 + + estore.Update(streamer, "channel", streamer.Channel, "latest_log_uid", streamer.LatestLogUid, "update_time", streamer.UpdateTime) } } diff --git a/utils.go b/utils.go index ee6a7d5..fda2b83 100644 --- a/utils.go +++ b/utils.go @@ -271,6 +271,10 @@ func NewWaitFor(wd selenium.WebDriver) *WaitFor { } func (wf *WaitFor) Default(xpath string, do func(elements ...selenium.WebElement) bool) error { + return wf.WaitWithTimeout(xpath, 15*time.Second, do) +} + +func (wf *WaitFor) WaitWithTimeout(xpath string, timeout time.Duration, do func(elements ...selenium.WebElement) bool) error { return wf.WebDriver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { elements, err := wd.FindElements(selenium.ByXPATH, xpath) if err != nil { @@ -288,5 +292,5 @@ func (wf *WaitFor) Default(xpath string, do func(elements ...selenium.WebElement } return false, nil - }, time.Second*15) + }, timeout) } From f86c2554077c94477b2ffc76649fe40019b16ae9 Mon Sep 17 00:00:00 2001 From: eson Date: Thu, 3 Sep 2020 14:17:54 +0800 Subject: [PATCH 07/18] finish nimo --- autostore_test.go | 28 +++++ extractor/nimo_extractor/nimo_extractor.go | 108 +++++++++++++++++- .../nimo_extractor/nimo_extractor_test.go | 77 ------------- supervisor_conf/nimo_extractor.conf | 10 ++ 4 files changed, 145 insertions(+), 78 deletions(-) create mode 100644 autostore_test.go create mode 100644 supervisor_conf/nimo_extractor.conf diff --git a/autostore_test.go b/autostore_test.go new file mode 100644 index 0000000..2c53220 --- /dev/null +++ b/autostore_test.go @@ -0,0 +1,28 @@ +package intimate + +import ( + "log" + "reflect" + "testing" +) + +type Store struct { +} + +func NewStore() *Store { + return &Store{} +} + +func (store *Store) Update(obj interface{}, objfields ...interface{}) { + ov := reflect.ValueOf(obj) + ot := ov.Type() + log.Printf("%#v,%#v", ov, ot) + log.Println(reflect.Indirect(reflect.ValueOf(objfields[0]))) +} + +func TestAutoStore(t *testing.T) { + store := NewStore() + streamer := &Streamer{} + + store.Update(streamer, streamer.Channel) +} diff --git a/extractor/nimo_extractor/nimo_extractor.go b/extractor/nimo_extractor/nimo_extractor.go index 375cf4c..f1bb1b5 100644 --- a/extractor/nimo_extractor/nimo_extractor.go +++ b/extractor/nimo_extractor/nimo_extractor.go @@ -1,9 +1,115 @@ package main -import "intimate" +import ( + "database/sql" + "intimate" + "log" + "time" + + "github.com/474420502/extractor" + "github.com/tebeka/selenium" +) // sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STNimo)) // estore 解析存储连接实例 var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() + +func main() { + Execute() +} + +type LiveInfo struct { + Followers int64 `exp:"//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2']" mth:"r:ExtractNumber"` + Views int64 `exp:"//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']" mth:"r:ExtractNumber"` + Channel string `exp:"//div[contains(@class,'nimo-rm_type')]//span"` + Gratuity []int64 `exp:"//div[contains(@class,'rank-item-after3')]//span[contains(@class,'nimo-currency__count')]"` +} + +func Execute() { + wd := intimate.GetChromeDriver(3030) + count := 0 + countlimit := 200 + + waitfor := intimate.NewWaitFor(wd) + ps := intimate.NewPerfectShutdown() + + for !ps.IsClose() { + streamer, err := estore.Pop(intimate.PNimo) + if err != nil { + log.Println(err) + estore.UpdateError(streamer, err) + continue + } + + wd.Get(streamer.LiveUrl.String) + // wd.Get("https://www.nimo.tv/live/1253835677") + + waitfor.Default("//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2' and text() != '']", nil) + waitfor.WaitWithTimeout("//div[contains(@class,'rank-item-top3')]", 7*time.Second, nil) + element, err := wd.FindElement(selenium.ByXPATH, "//div[contains(@class,'rank-item-top3')]") + if err != nil { + log.Println(streamer.Uid, err) + } else { + err = element.MoveTo(50, 50) + element.Click() + if err != nil { + log.Println(streamer.Uid, err) + } + } + waitfor.Default("//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']", nil) + + var pagesource string + pagesource, _ = wd.PageSource() + + etor := extractor.ExtractHtmlString(pagesource) + li := etor.GetObjectByTag(LiveInfo{}).(*LiveInfo) + // log.Printf("%#v", li) + + utime := sql.NullTime{Time: time.Now(), Valid: true} + + clog := &intimate.CollectLog{} + clog.Platform = intimate.PNimo + clog.Followers = sql.NullInt64{Int64: li.Followers, Valid: true} + clog.Views = sql.NullInt64{Int64: li.Views, Valid: true} + clog.UpdateTime = utime + clog.StreamerUid = streamer.Uid + + var sum int64 = 0 + for _, v := range li.Gratuity { + sum += v + } + clog.Gratuity = sql.NullInt64{Int64: sum, Valid: true} + + cuid := estore.InsertClog(clog) + + streamer.Channel = sql.NullString{String: li.Channel, Valid: true} + streamer.LatestLogUid = cuid + streamer.UpdateTime = utime + streamer.Operator = 0 + + switch { + case li.Followers <= 1000: + streamer.UpdateInterval = 720 + case li.Followers <= 10000: + streamer.UpdateInterval = 360 + case li.Followers <= 100000: + streamer.UpdateInterval = 180 + case li.Followers <= 1000000: + streamer.UpdateInterval = 90 + default: + streamer.UpdateInterval = 60 + } + + estore.Update(streamer, "update_interval", streamer.UpdateInterval, "operator", streamer.Operator, "channel", streamer.Channel, "latest_log_uid", streamer.LatestLogUid, "update_time", streamer.UpdateTime) + + count++ + if count >= countlimit { + count = 0 + wd.Close() + wd.Quit() + wd = intimate.GetChromeDriver(3030) + } + } +} diff --git a/extractor/nimo_extractor/nimo_extractor_test.go b/extractor/nimo_extractor/nimo_extractor_test.go index 5491776..b80dba9 100644 --- a/extractor/nimo_extractor/nimo_extractor_test.go +++ b/extractor/nimo_extractor/nimo_extractor_test.go @@ -1,86 +1,9 @@ package main import ( - "database/sql" - "intimate" - "log" "testing" - "time" - - "github.com/474420502/extractor" - "github.com/tebeka/selenium" ) func TestMain(t *testing.T) { Execute() } - -type LiveInfo struct { - Followers int64 `exp:"//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2']" mth:"r:ExtractNumber"` - Views int64 `exp:"//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']" mth:"r:ExtractNumber"` - Channel string `exp:"//div[contains(@class,'nimo-rm_type')]//span"` - Gratuity []int64 `exp:"//div[contains(@class,'rank-item-after3')]//span[contains(@class,'nimo-currency__count')]"` -} - -func Execute() { - wd := intimate.GetChromeDriver(3031) - waitfor := intimate.NewWaitFor(wd) - ps := intimate.NewPerfectShutdown() - - for !ps.IsClose() { - streamer, err := estore.Pop(intimate.PNimo) - if err != nil { - log.Println(err) - estore.UpdateError(streamer, err) - continue - } - - wd.Get(streamer.LiveUrl.String) - // wd.Get("https://www.nimo.tv/live/1253835677") - - waitfor.Default("//div[contains(@class,'nimo-rm_followers')]//span[@class='text c2' and text() != '']", nil) - waitfor.WaitWithTimeout("//div[contains(@class,'rank-item-top3')]", 7*time.Second, nil) - element, err := wd.FindElement(selenium.ByXPATH, "//div[contains(@class,'rank-item-top3')]") - if err != nil { - log.Println(streamer.Uid, err) - } else { - err = element.MoveTo(50, 50) - element.Click() - if err != nil { - log.Println(streamer.Uid, err) - } - } - waitfor.Default("//div[contains(@class,'nimo-rm_audience')]//span[@class='text c2']", nil) - - var pagesource string - pagesource, _ = wd.PageSource() - - etor := extractor.ExtractHtmlString(pagesource) - li := etor.GetObjectByTag(LiveInfo{}).(*LiveInfo) - // log.Printf("%#v", li) - - utime := sql.NullTime{Time: time.Now(), Valid: true} - - clog := &intimate.CollectLog{} - clog.Platform = intimate.PNimo - clog.Followers = sql.NullInt64{Int64: li.Followers, Valid: true} - clog.Views = sql.NullInt64{Int64: li.Views, Valid: true} - clog.UpdateTime = utime - clog.StreamerUid = streamer.Uid - - var sum int64 = 0 - for _, v := range li.Gratuity { - sum += v - } - clog.Gratuity = sql.NullInt64{Int64: sum, Valid: true} - - cuid := estore.InsertClog(clog) - - streamer.Channel = sql.NullString{String: li.Channel, Valid: true} - streamer.LatestLogUid = cuid - streamer.UpdateTime = utime - streamer.Operator = 0 - - estore.Update(streamer, "channel", streamer.Channel, "latest_log_uid", streamer.LatestLogUid, "update_time", streamer.UpdateTime) - } -} diff --git a/supervisor_conf/nimo_extractor.conf b/supervisor_conf/nimo_extractor.conf new file mode 100644 index 0000000..fccd98c --- /dev/null +++ b/supervisor_conf/nimo_extractor.conf @@ -0,0 +1,10 @@ +[supervisord] +nodaemon=true + +[program:nimo_extractor] +directory = MYPATH/bin/nimo_extractor/ +command= MYPATH/bin/nimo_extractor/nimo_extractor +autorestart=true +stderr_logfile=MYPATH/bin/nimo_extractor/log +stderr_logfile_maxbytes=0 +stopsignal=QUIT From 2236e13af704a5ea9fbdefc42dd5f202672ba9dc Mon Sep 17 00:00:00 2001 From: eson Date: Thu, 3 Sep 2020 18:50:32 +0800 Subject: [PATCH 08/18] TODO: autostore --- autostore_test.go | 157 +++++++++++++++++++++++++++++++++++++++++---- extractor_field.go | 4 +- 2 files changed, 148 insertions(+), 13 deletions(-) diff --git a/autostore_test.go b/autostore_test.go index 2c53220..926573a 100644 --- a/autostore_test.go +++ b/autostore_test.go @@ -1,28 +1,163 @@ package intimate import ( - "log" + "database/sql" + "fmt" "reflect" "testing" ) type Store struct { + db *sql.DB } -func NewStore() *Store { - return &Store{} +type Table struct { + store *Store + name string + setting interface{} + + updatesql string + selectsql string + insertsql string } -func (store *Store) Update(obj interface{}, objfields ...interface{}) { - ov := reflect.ValueOf(obj) - ot := ov.Type() - log.Printf("%#v,%#v", ov, ot) - log.Println(reflect.Indirect(reflect.ValueOf(objfields[0]))) +// const updatesql = "UPDATE %s SET %s WHERE %s = ?" + +func NewStore(uri string) *Store { + db, err := sql.Open("mysql", uri) + if err != nil { + panic(err) + } + s := &Store{db: db} + return s +} + +func (store *Store) Table(name string) *Table { + table := &Table{store: store} + table.name = name + + table.insertsql = `INSERT INTO ` + table.name + `(%s) values(%s)` + table.updatesql = `UPDATE ` + table.name + ` SET %s WHERE %s = ?` + + return table +} + +type Queue struct { + table *Table + obj reflect.Type +} + +func (t *Table) Insert(obj interface{}) error { + ov := reflect.ValueOf(obj).Elem() + ot := reflect.TypeOf(obj) + + fieldsql := "" + argssql := "" + + var args []interface{} + for i := 0; i < ov.NumField(); i++ { + field := ov.Field(i) + ftype := ot.Elem().Field(i) + + if fname, ok := ftype.Tag.Lookup("field"); ok { + if flag, ok := ftype.Tag.Lookup("uid"); ok { + if flag == "auto" { + continue + } + } + + k := ftype.Type.Kind() + if k == reflect.Ptr || k == reflect.Interface { + if !field.IsNil() { + felem := field.Elem() + args = append(args, felem.Interface()) + fieldsql += fname + "," + argssql += "?," + } + } else { + args = append(args, field.Interface()) + fieldsql += fname + "," + argssql += "?," + } + + } + + } + + ssql := fmt.Sprintf(t.insertsql, fieldsql[:len(fieldsql)-1], argssql[:len(argssql)-1]) + _, err := t.store.db.Exec(ssql, args...) + return err +} + +func (t *Table) Update(obj interface{}) error { + + ov := reflect.ValueOf(obj).Elem() + ot := reflect.TypeOf(obj) + + fieldsql := "" + var uidname string + var uidvalue interface{} + + var args []interface{} + for i := 0; i < ov.NumField(); i++ { + field := ov.Field(i) + ftype := ot.Elem().Field(i) + + if fname, ok := ftype.Tag.Lookup("field"); ok { + if _, ok := ftype.Tag.Lookup("uid"); ok { + if uidvalue != nil { + panic(fmt.Errorf("uid must unique, %s and %s", uidname, fname)) + } + uidname = fname + uidvalue = field.Interface() + continue + } + + k := ftype.Type.Kind() + if k == reflect.Ptr || k == reflect.Interface { + if !field.IsNil() { + felem := field.Elem() + args = append(args, felem.Interface()) + fieldsql += fname + " = ?," + } + } else { + args = append(args, field.Interface()) + fieldsql += fname + " = ?," + } + + } + + } + + if uidvalue == nil { + panic(fmt.Errorf("update must contain `uid` tag")) + } + + usql := fmt.Sprintf(t.updatesql, fieldsql[:len(fieldsql)-1], uidname) + args = append(args, uidvalue) + _, err := t.store.db.Exec(usql, args...) + return err +} + +type TSreamer struct { + Uid int `field:"uid" uid:"auto"` + Name interface{} `field:"name"` + UserID *sql.NullString `field:"userid"` + Ext *sql.NullString `field:"ext"` + Iface interface{} `field:"tag"` } func TestAutoStore(t *testing.T) { - store := NewStore() - streamer := &Streamer{} + uri := "root:@tcp(127.0.0.1:4000)/test?parseTime=true&loc=Local&charset=utf8mb4&collation=utf8mb4_unicode_ci" + store := NewStore(uri) + streamer := &TSreamer{} - store.Update(streamer, streamer.Channel) + streamer.Uid = 2 + streamer.UserID = nil + streamer.Name = "streamer" + streamer.Ext = &sql.NullString{String: "ext", Valid: true} + err := store.Table("streamer").Update(streamer) + if err != nil { + t.Error(err) + } } diff --git a/extractor_field.go b/extractor_field.go index 1adda5e..91a6f4a 100644 --- a/extractor_field.go +++ b/extractor_field.go @@ -38,8 +38,8 @@ func (sl *StreamerList) Set(field string, value interface{}) { } type Streamer struct { - Uid int64 // - Platform Platform // + Uid int64 `field:"uid" uid:"auto"` // + Platform Platform `field:"platform"` // UserId string // UserName sql.NullString // From 83dcdf86c9a7ce47094f4b913ed6b22e1c249259 Mon Sep 17 00:00:00 2001 From: eson Date: Fri, 4 Sep 2020 19:01:51 +0800 Subject: [PATCH 09/18] TODO: 2 --- autostore_test.go | 231 +++++++++++++++++++++++++--- convert.go | 378 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 586 insertions(+), 23 deletions(-) create mode 100644 convert.go diff --git a/autostore_test.go b/autostore_test.go index 926573a..286fb56 100644 --- a/autostore_test.go +++ b/autostore_test.go @@ -2,8 +2,11 @@ package intimate import ( "database/sql" + "encoding/binary" "fmt" + "log" "reflect" + "strconv" "testing" ) @@ -38,13 +41,209 @@ func (store *Store) Table(name string) *Table { table.insertsql = `INSERT INTO ` + table.name + `(%s) values(%s)` table.updatesql = `UPDATE ` + table.name + ` SET %s WHERE %s = ?` - + // table.selectsql = `FROM ` + table.name + `WHERE operator` return table } type Queue struct { - table *Table - obj reflect.Type + table *Table + obj reflect.Type + selected string + condition string + uidname string + uididx int +} + +type OperatorType string + +const ( + OP_OK OperatorType = "0" + OP_WAIT OperatorType = "1000" + OP_ERROR OperatorType = "10000" +) + +func (queue *Queue) Pop() (result interface{}, err error) { + + db := queue.table.store.db + tx, err := db.Begin() + if err != nil { + return nil, err + } + + defer func() { + cerr := tx.Commit() + if cerr != nil { + log.Println(cerr) + log.Println(tx.Rollback()) + } + }() + + selectsql := `SELECT ` + queue.selected + ` FROM ` + queue.table.name + ` WHERE ` + queue.condition + " limit 1 for update" + rows, err := tx.Query(selectsql) + // err = rows.Err() + if err != nil { + return nil, fmt.Errorf("table: %s queue is empty", queue.table.name) + } + + var fields = make([]interface{}, queue.obj.NumField()) + for i := range fields { + var iv interface{} + fields[i] = &iv + } + + // if !rows.Next() { + // return nil, fmt.Errorf("table: %s queue is empty", queue.table.name) + // } + if rows.Next() { + err = rows.Scan(fields...) + if err != nil { + return nil, err + } + } + + columntypes, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + if err = rows.Close(); err != nil { + return nil, err + } + + _, err = tx.Exec("UPDATE "+queue.table.name+" SET operator = "+string(OP_WAIT)+" WHERE "+queue.uidname+" = ?", fields[queue.uididx]) + if err != nil { + log.Println(err) + return nil, err + } + + obj := reflect.New(queue.obj).Elem() + for i := 0; i < obj.NumField(); i++ { + field := obj.Field(i) + convert(*fields[i].(*interface{}), field, columntypes[i]) + // if field.Type().Kind() == reflect.Ptr { + // field.Elem().Set(reflect.ValueOf(*fields[i].(*interface{}))) + // continue + // } + // field.Set(reflect.ValueOf(*fields[i].(*interface{}))) + } + + return obj.Interface(), err +} + +func TestAutoStore(t *testing.T) { + uri := "root:@tcp(127.0.0.1:4000)/test?parseTime=true&loc=Local&charset=utf8mb4&collation=utf8mb4_unicode_ci" + store := NewStore(uri) + + queue := store.Table("streamer").Queue(TSreamer{}, "operator = 0") + t.Error(queue.Pop()) + + streamer := &TSreamer{} + + streamer.Uid = 2 + streamer.UserID = &sql.NullString{String: "xixi", Valid: true} + streamer.Name = "streamer" + streamer.Operator = 0 + streamer.Ext = &sql.NullString{String: "ext", Valid: true} + err := store.Table("streamer").Insert(streamer) + if err != nil { + t.Error(err) + } +} + +func convert(dest interface{}, field reflect.Value, columntype *sql.ColumnType) error { + + log.Println("type:", field.Type(), ",kind:", field.Kind(), ",field:", field) + if field.Kind() == reflect.Ptr { + fn := field.Type().Elem().Name() // New 一个 field.Type().Elem() . 然后判断 columntype 转化 成 NullString Time + field = field.Elem() // + log.Println("type:", fn, ",kind:", field.Kind(), ",field:", field) + } + + if field.Kind() == reflect.Interface { + + } + + // log.Println(field.Kind(), field, reflect.TypeOf(field).Elem().Name(), columntype.ScanType().Kind()) + + switch fv := field.Kind(); fv { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if dest == nil { + return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) + } + + log.Println(binary.Varint(dest.([]byte))) + s := asString(dest) + i64, err := strconv.ParseInt(s, 10, field.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + } + field.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if dest == nil { + return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) + } + s := asString(dest) + u64, err := strconv.ParseUint(s, 10, field.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + } + field.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + if dest == nil { + return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) + } + s := asString(dest) + f64, err := strconv.ParseFloat(s, field.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + } + field.SetFloat(f64) + return nil + case reflect.String: + if dest == nil { + return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) + } + switch v := dest.(type) { + case string: + field.SetString(v) + return nil + case []byte: + field.SetString(string(v)) + return nil + } + default: + + // log.Println(fv, columntype.ScanType().Kind()) + } + + return nil +} + +func (t *Table) Queue(obj interface{}, whereCondition string) *Queue { + q := &Queue{} + q.condition = whereCondition + q.obj = reflect.TypeOf(obj) + q.table = t + + for i := 0; i < q.obj.NumField(); i++ { + field := q.obj.Field(i) + if fname, ok := field.Tag.Lookup("field"); ok { + q.selected += fname + "," + if _, ok := field.Tag.Lookup("uid"); ok { + q.uididx = i + q.uidname = fname + } + } + + } + + q.selected = q.selected[:len(q.selected)-1] + return q } func (t *Table) Insert(obj interface{}) error { @@ -140,24 +339,10 @@ func (t *Table) Update(obj interface{}) error { } type TSreamer struct { - Uid int `field:"uid" uid:"auto"` - Name interface{} `field:"name"` - UserID *sql.NullString `field:"userid"` - Ext *sql.NullString `field:"ext"` - Iface interface{} `field:"tag"` -} - -func TestAutoStore(t *testing.T) { - uri := "root:@tcp(127.0.0.1:4000)/test?parseTime=true&loc=Local&charset=utf8mb4&collation=utf8mb4_unicode_ci" - store := NewStore(uri) - streamer := &TSreamer{} - - streamer.Uid = 2 - streamer.UserID = nil - streamer.Name = "streamer" - streamer.Ext = &sql.NullString{String: "ext", Valid: true} - err := store.Table("streamer").Update(streamer) - if err != nil { - t.Error(err) - } + Uid int `field:"uid" uid:"auto"` + Name interface{} `field:"name"` + UserID *sql.NullString `field:"userid"` + Ext *sql.NullString `field:"ext"` + Iface interface{} `field:"tag"` + Operator int `field:"operator"` } diff --git a/convert.go b/convert.go new file mode 100644 index 0000000..4e8d149 --- /dev/null +++ b/convert.go @@ -0,0 +1,378 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Type conversions for Scan. + +package intimate + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "reflect" + "strconv" + "time" +) + +var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error + +// convertAssignRows copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. If rows is passed in, the rows will +// be used as the parent for any cursor values converted from a +// driver.Rows to a *Rows. +func convertAssignRows(dest, src interface{}, rows *sql.Rows) error { + // Common cases, without reflect. + switch s := src.(type) { + case string: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = s + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = append((*d)[:0], s...) + return nil + } + case []byte: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = string(s) + return nil + case *interface{}: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s + return nil + } + case time.Time: + switch d := dest.(type) { + case *time.Time: + *d = s + return nil + case *string: + *d = s.Format(time.RFC3339Nano) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s.Format(time.RFC3339Nano)) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) + return nil + } + case decimalDecompose: + switch d := dest.(type) { + case decimalCompose: + return d.Compose(s.Decompose(nil)) + } + case nil: + switch d := dest.(type) { + case *interface{}: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = nil + return nil + } + // The driver is returning a cursor the client may iterate over. + } + + var sv reflect.Value + + switch d := dest.(type) { + case *string: + sv = reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + *d = asString(src) + return nil + } + case *[]byte: + sv = reflect.ValueOf(src) + if b, ok := asBytes(nil, sv); ok { + *d = b + return nil + } + case *sql.RawBytes: + sv = reflect.ValueOf(src) + if b, ok := asBytes([]byte(*d)[:0], sv); ok { + *d = sql.RawBytes(b) + return nil + } + case *bool: + bv, err := driver.Bool.ConvertValue(src) + if err == nil { + *d = bv.(bool) + } + return err + case *interface{}: + *d = src + return nil + } + + if scanner, ok := dest.(sql.Scanner); ok { + return scanner.Scan(src) + } + + dpv := reflect.ValueOf(dest) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + if dpv.IsNil() { + return errNilPtr + } + + if !sv.IsValid() { + sv = reflect.ValueOf(src) + } + + dv := reflect.Indirect(dpv) + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { + switch b := src.(type) { + case []byte: + dv.Set(reflect.ValueOf(cloneBytes(b))) + default: + dv.Set(sv) + } + return nil + } + + if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + + // The following conversions use a string value as an intermediate representation + // to convert between various numeric types. + // + // This also allows scanning into user defined types such as "type Int int64". + // For symmetry, also check for string destination types. + switch dv.Kind() { + case reflect.Ptr: + if src == nil { + dv.Set(reflect.Zero(dv.Type())) + return nil + } + dv.Set(reflect.New(dv.Type().Elem())) + return convertAssignRows(dv.Interface(), src, rows) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if src == nil { + return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) + } + s := asString(src) + i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if src == nil { + return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) + } + s := asString(src) + u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + if src == nil { + return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) + } + s := asString(src) + f64, err := strconv.ParseFloat(s, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetFloat(f64) + return nil + case reflect.String: + if src == nil { + return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) + } + switch v := src.(type) { + case string: + dv.SetString(v) + return nil + case []byte: + dv.SetString(string(v)) + return nil + } + } + + return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) +} + +func strconvErr(err error) error { + if ne, ok := err.(*strconv.NumError); ok { + return ne.Err + } + return err +} + +func cloneBytes(b []byte) []byte { + if b == nil { + return nil + } + c := make([]byte, len(b)) + copy(c, b) + return c +} + +func asString(src interface{}) string { + switch v := src.(type) { + case string: + return v + case []byte: + return string(v) + } + rv := reflect.ValueOf(src) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(rv.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(rv.Uint(), 10) + case reflect.Float64: + return strconv.FormatFloat(rv.Float(), 'g', -1, 64) + case reflect.Float32: + return strconv.FormatFloat(rv.Float(), 'g', -1, 32) + case reflect.Bool: + return strconv.FormatBool(rv.Bool()) + } + return fmt.Sprintf("%v", src) +} + +func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.AppendInt(buf, rv.Int(), 10), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.AppendUint(buf, rv.Uint(), 10), true + case reflect.Float32: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true + case reflect.Float64: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true + case reflect.Bool: + return strconv.AppendBool(buf, rv.Bool()), true + case reflect.String: + s := rv.String() + return append(buf, s...), true + } + return +} + +var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() + +// callValuerValue returns vr.Value(), with one exception: +// If vr.Value is an auto-generated method on a pointer type and the +// pointer is nil, it would panic at runtime in the panicwrap +// method. Treat it like nil instead. +// Issue 8415. +// +// This is so people can implement driver.Value on value types and +// still use nil pointers to those types to mean nil/NULL, just like +// string/*string. +// +// This function is mirrored in the database/sql/driver package. +func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { + if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && + rv.IsNil() && + rv.Type().Elem().Implements(valuerReflectType) { + return nil, nil + } + return vr.Value() +} + +// decimal composes or decomposes a decimal value to and from individual parts. +// There are four parts: a boolean negative flag, a form byte with three possible states +// (finite=0, infinite=1, NaN=2), a base-2 big-endian integer +// coefficient (also known as a significand) as a []byte, and an int32 exponent. +// These are composed into a final value as "decimal = (neg) (form=finite) coefficient * 10 ^ exponent". +// A zero length coefficient is a zero value. +// The big-endian integer coefficient stores the most significant byte first (at coefficient[0]). +// If the form is not finite the coefficient and exponent should be ignored. +// The negative parameter may be set to true for any form, although implementations are not required +// to respect the negative parameter in the non-finite form. +// +// Implementations may choose to set the negative parameter to true on a zero or NaN value, +// but implementations that do not differentiate between negative and positive +// zero or NaN values should ignore the negative parameter without error. +// If an implementation does not support Infinity it may be converted into a NaN without error. +// If a value is set that is larger than what is supported by an implementation, +// an error must be returned. +// Implementations must return an error if a NaN or Infinity is attempted to be set while neither +// are supported. +// +// NOTE(kardianos): This is an experimental interface. See https://golang.org/issue/30870 +type decimal interface { + decimalDecompose + decimalCompose +} + +type decimalDecompose interface { + // Decompose returns the internal decimal state in parts. + // If the provided buf has sufficient capacity, buf may be returned as the coefficient with + // the value set and length set as appropriate. + Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) +} + +type decimalCompose interface { + // Compose sets the internal decimal value from parts. If the value cannot be + // represented then an error should be returned. + Compose(form byte, negative bool, coefficient []byte, exponent int32) error +} From d3689a0c8b2e33ad3d0e85b26960a480725fb852 Mon Sep 17 00:00:00 2001 From: eson Date: Mon, 7 Sep 2020 15:13:50 +0800 Subject: [PATCH 10/18] TODO: sql to time.Time Type --- autostore_test.go | 223 ++++++++++++++++++++++++++++++++++------------ build.sh | 2 +- go.mod | 1 + 3 files changed, 170 insertions(+), 56 deletions(-) diff --git a/autostore_test.go b/autostore_test.go index 286fb56..7e4a808 100644 --- a/autostore_test.go +++ b/autostore_test.go @@ -3,11 +3,14 @@ package intimate import ( "database/sql" "encoding/binary" + "encoding/json" "fmt" "log" "reflect" "strconv" "testing" + + "github.com/davecgh/go-spew/spew" ) type Store struct { @@ -120,14 +123,9 @@ func (queue *Queue) Pop() (result interface{}, err error) { for i := 0; i < obj.NumField(); i++ { field := obj.Field(i) convert(*fields[i].(*interface{}), field, columntypes[i]) - // if field.Type().Kind() == reflect.Ptr { - // field.Elem().Set(reflect.ValueOf(*fields[i].(*interface{}))) - // continue - // } - // field.Set(reflect.ValueOf(*fields[i].(*interface{}))) } - return obj.Interface(), err + return obj.Addr().Interface(), err } func TestAutoStore(t *testing.T) { @@ -135,90 +133,204 @@ func TestAutoStore(t *testing.T) { store := NewStore(uri) queue := store.Table("streamer").Queue(TSreamer{}, "operator = 0") - t.Error(queue.Pop()) + re, _ := queue.Pop() + + pstreamer := re.(*TSreamer) + m := make(map[string]interface{}) + json.Unmarshal(pstreamer.Iface.([]byte), &m) + spew.Println(re.(*TSreamer), m) streamer := &TSreamer{} streamer.Uid = 2 - streamer.UserID = &sql.NullString{String: "xixi", Valid: true} + streamer.UserID = &sql.NullString{String: "hehe", Valid: true} streamer.Name = "streamer" streamer.Operator = 0 + streamer.Bit = 0b11 streamer.Ext = &sql.NullString{String: "ext", Valid: true} - err := store.Table("streamer").Insert(streamer) + + tag := make(map[string]interface{}) + tag["json"] = true + tag["name"] = "test" + btag, err := json.Marshal(tag) + if err != nil { + t.Error(err) + } + streamer.Iface = btag + + err = store.Table("streamer").Insert(streamer) if err != nil { t.Error(err) } } - -func convert(dest interface{}, field reflect.Value, columntype *sql.ColumnType) error { - - log.Println("type:", field.Type(), ",kind:", field.Kind(), ",field:", field) - if field.Kind() == reflect.Ptr { - fn := field.Type().Elem().Name() // New 一个 field.Type().Elem() . 然后判断 columntype 转化 成 NullString Time - field = field.Elem() // - log.Println("type:", fn, ",kind:", field.Kind(), ",field:", field) - } - - if field.Kind() == reflect.Interface { - - } - - // log.Println(field.Kind(), field, reflect.TypeOf(field).Elem().Name(), columntype.ScanType().Kind()) - - switch fv := field.Kind(); fv { +func assign(field reflect.Value, dest interface{}) (bool, error) { + switch field.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if dest == nil { - return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) - } - log.Println(binary.Varint(dest.([]byte))) s := asString(dest) i64, err := strconv.ParseInt(s, 10, field.Type().Bits()) if err != nil { err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) } field.SetInt(i64) - return nil + return false, nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - if dest == nil { - return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) - } + s := asString(dest) u64, err := strconv.ParseUint(s, 10, field.Type().Bits()) if err != nil { err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) } field.SetUint(u64) - return nil + return false, nil case reflect.Float32, reflect.Float64: - if dest == nil { - return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) - } s := asString(dest) f64, err := strconv.ParseFloat(s, field.Type().Bits()) if err != nil { err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) } field.SetFloat(f64) - return nil + return false, nil case reflect.String: - if dest == nil { - return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) - } - switch v := dest.(type) { - case string: - field.SetString(v) - return nil - case []byte: - field.SetString(string(v)) - return nil - } - default: + field.SetString(string(dest.([]byte))) + return false, nil + case reflect.Interface: + return true, nil + } - // log.Println(fv, columntype.ScanType().Kind()) + return false, fmt.Errorf("") +} +func convert(dest interface{}, field reflect.Value, columntype *sql.ColumnType) error { + + log.Println("type:", field.Type(), ",kind:", field.Kind(), ",field:", field, "scanType:", columntype.ScanType(), "databaseType:", columntype.DatabaseTypeName()) + if field.Kind() == reflect.Ptr { + fn := field.Type().Elem() // New 一个 field.Type().Elem() . 然后判断 columntype 转化 成 NullString Time + field.Set(reflect.New(fn)) + field = field.Elem() + log.Println("type:", fn.Name(), ",kind:", field.Kind(), ",fieldtype:", field.Type()) + } + + // log.Println(field.Kind(), field, reflect.TypeOf(field).Elem().Name(), columntype.ScanType().Kind()) + + if dest == nil { + return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) + } + + switch columntype.DatabaseTypeName() { + case "TINYINT": + fallthrough + case "SMALLINT": + fallthrough + case "MEDIUMINT": + fallthrough + case "INT": + fallthrough + case "BIGINT": + + isdefault, err := assign(field, dest) + if err != nil { + return err + } + if isdefault { + s := asString(dest) + i64, err := strconv.ParseInt(s, 10, 64) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + } + // reflect.New(reflect.TypeOf(i64)) + field.Set(reflect.ValueOf(i64)) + } + return nil + + case "FLOAT": + fallthrough + case "DOUBLE": + fallthrough + case "DECIMAL": + isdefault, err := assign(field, dest) + if err != nil { + return err + } + if isdefault { + s := asString(dest) + f64, err := strconv.ParseFloat(s, 64) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) + } + field.Set(reflect.ValueOf(f64)) + } + return nil + + case "BINARY": + fallthrough + case "VARBINARY": + fallthrough + case "TINYBLOB": + fallthrough + case "BLOB": + fallthrough + case "MEDIUMBLOB": + fallthrough + case "LONGBLOB": + fallthrough + case "JSON": + isdefault, err := assign(field, dest) + if err != nil { + return err + } + if isdefault { + field.Set(reflect.ValueOf(dest.([]byte))) + } + case "CHAR": + fallthrough + case "VARCHAR": + fallthrough + case "TINYTEXT": + fallthrough + case "TEXT": + fallthrough + case "MEDIUMTEXT": + fallthrough + case "LONGTEXT": + isdefault, err := assign(field, dest) + if err != nil { + return err + } + if isdefault { + field.Set(reflect.ValueOf(string(dest.([]byte)))) + } + return nil + case "BIT": + var bits []byte = make([]byte, 8) + copy(bits, dest.([]byte)) + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + field.SetInt(int64(binary.LittleEndian.Uint64(bits))) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + field.SetUint(binary.LittleEndian.Uint64(bits)) + return nil + case reflect.Interface: + field.Set(reflect.ValueOf(binary.LittleEndian.Uint64(bits))) + return nil + } + + return nil + } + + // log.Println(fv, columntype.ScanType().Kind()) + + if iscan, ok := field.Addr().Interface().(sql.Scanner); ok { + err := iscan.Scan(dest) + if err != nil { + return err + } + return nil } return nil @@ -344,5 +456,6 @@ type TSreamer struct { UserID *sql.NullString `field:"userid"` Ext *sql.NullString `field:"ext"` Iface interface{} `field:"tag"` + Bit uint64 `field:"bit"` Operator int `field:"operator"` } diff --git a/build.sh b/build.sh index f92ccd4..19765fe 100644 --- a/build.sh +++ b/build.sh @@ -20,4 +20,4 @@ do projectworkspace=$src/bin/$projectname cd $path && mkdir $projectworkspace -p && go build -o $projectworkspace/$projectname cd $src -done +done \ No newline at end of file diff --git a/go.mod b/go.mod index ca8b0a7..1107f9c 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/474420502/focus v0.12.0 github.com/474420502/gcurl v0.4.5 github.com/474420502/requests v1.9.1 + github.com/davecgh/go-spew v1.1.1 github.com/go-sql-driver/mysql v1.5.0 github.com/lestrrat-go/libxml2 v0.0.0-20200215080510-6483566f52cb github.com/tebeka/selenium v0.9.9 From 1590fa0c82fb631632112c9b597116b43368ce11 Mon Sep 17 00:00:00 2001 From: eson Date: Mon, 7 Sep 2020 16:54:03 +0800 Subject: [PATCH 11/18] add: autostore todo: autostore replace old store --- autostore.go | 325 +++++++++++++++++++++++++++++++++++++++++ autostore_test.go | 362 ++-------------------------------------------- 2 files changed, 338 insertions(+), 349 deletions(-) create mode 100644 autostore.go diff --git a/autostore.go b/autostore.go new file mode 100644 index 0000000..48c3f4f --- /dev/null +++ b/autostore.go @@ -0,0 +1,325 @@ +package intimate + +import ( + "database/sql" + "encoding/binary" + "fmt" + "log" + "reflect" + "strconv" + "time" +) + +type Store struct { + db *sql.DB +} + +type Table struct { + store *Store + name string + setting interface{} + + updatesql string + selectsql string + insertsql string +} + +// const updatesql = "UPDATE %s SET %s WHERE %s = ?" + +func NewStore(uri string) *Store { + db, err := sql.Open("mysql", uri) + if err != nil { + panic(err) + } + s := &Store{db: db} + return s +} + +func (store *Store) Table(name string) *Table { + table := &Table{store: store} + table.name = name + + table.insertsql = `INSERT INTO ` + table.name + `(%s) values(%s)` + table.updatesql = `UPDATE ` + table.name + ` SET %s WHERE %s = ?` + // table.selectsql = `FROM ` + table.name + `WHERE operator` + return table +} + +type Queue struct { + table *Table + obj reflect.Type + selected string + condition string + uidname string + uididx int +} + +// OperatorType 字典Operator 标志位的类型 +type OperatorType string + +const ( + // OpOK 正常 + OpOK OperatorType = "0" + // OpWAIT 等待处理 + OpWAIT OperatorType = "1000" + // OpERROR 错误处理 + OpERROR OperatorType = "10000" +) + +func (t *Table) Queue(obj interface{}, whereCondition string) *Queue { + q := &Queue{} + q.condition = whereCondition + q.obj = reflect.TypeOf(obj) + q.table = t + + for i := 0; i < q.obj.NumField(); i++ { + field := q.obj.Field(i) + if fname, ok := field.Tag.Lookup("field"); ok { + q.selected += fname + "," + if _, ok := field.Tag.Lookup("uid"); ok { + q.uididx = i + q.uidname = fname + } + } + + } + + q.selected = q.selected[:len(q.selected)-1] + return q +} + +func (t *Table) Insert(obj interface{}) error { + ov := reflect.ValueOf(obj).Elem() + ot := reflect.TypeOf(obj) + + fieldsql := "" + argssql := "" + + var args []interface{} + for i := 0; i < ov.NumField(); i++ { + field := ov.Field(i) + ftype := ot.Elem().Field(i) + + if fname, ok := ftype.Tag.Lookup("field"); ok { + if flag, ok := ftype.Tag.Lookup("uid"); ok { + if flag == "auto" { + continue + } + } + + k := ftype.Type.Kind() + if k == reflect.Ptr || k == reflect.Interface { + if !field.IsNil() { + felem := field.Elem() + args = append(args, felem.Interface()) + fieldsql += fname + "," + argssql += "?," + } + } else { + args = append(args, field.Interface()) + fieldsql += fname + "," + argssql += "?," + } + + } + + } + + ssql := fmt.Sprintf(t.insertsql, fieldsql[:len(fieldsql)-1], argssql[:len(argssql)-1]) + _, err := t.store.db.Exec(ssql, args...) + return err +} + +func (t *Table) Update(obj interface{}) error { + + ov := reflect.ValueOf(obj).Elem() + ot := reflect.TypeOf(obj) + + fieldsql := "" + var uidname string + var uidvalue interface{} + + var args []interface{} + for i := 0; i < ov.NumField(); i++ { + field := ov.Field(i) + ftype := ot.Elem().Field(i) + + if fname, ok := ftype.Tag.Lookup("field"); ok { + if _, ok := ftype.Tag.Lookup("uid"); ok { + if uidvalue != nil { + panic(fmt.Errorf("uid must unique, %s and %s", uidname, fname)) + } + uidname = fname + uidvalue = field.Interface() + continue + } + + k := ftype.Type.Kind() + if k == reflect.Ptr || k == reflect.Interface { + if !field.IsNil() { + felem := field.Elem() + args = append(args, felem.Interface()) + fieldsql += fname + " = ?," + } + } else { + args = append(args, field.Interface()) + fieldsql += fname + " = ?," + } + + } + + } + + if uidvalue == nil { + panic(fmt.Errorf("update must contain `uid` tag")) + } + + usql := fmt.Sprintf(t.updatesql, fieldsql[:len(fieldsql)-1], uidname) + args = append(args, uidvalue) + _, err := t.store.db.Exec(usql, args...) + return err +} + +func assign(field reflect.Value, src interface{}) (bool, error) { + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := asString(src) + i64, err := strconv.ParseInt(s, 10, field.Type().Bits()) + if err != nil { + err = strconvErr(err) + return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, field.Kind(), err) + } + field.SetInt(i64) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + + s := asString(src) + u64, err := strconv.ParseUint(s, 10, field.Type().Bits()) + if err != nil { + err = strconvErr(err) + return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, field.Kind(), err) + } + field.SetUint(u64) + case reflect.Float32, reflect.Float64: + s := asString(src) + f64, err := strconv.ParseFloat(s, field.Type().Bits()) + if err != nil { + err = strconvErr(err) + return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, field.Kind(), err) + } + field.SetFloat(f64) + case reflect.String: + field.SetString(string(src.([]byte))) + case reflect.Interface: + return true, nil + } + + return false, nil +} + +func convert(src interface{}, field reflect.Value, columntype *sql.ColumnType) error { + + log.Println("type:", field.Type(), ",kind:", field.Kind(), ",field:", field, "scanType:", columntype.ScanType(), "databaseType:", columntype.DatabaseTypeName()) + if field.Kind() == reflect.Ptr { + fn := field.Type().Elem() // New 一个 field.Type().Elem() . 然后判断 columntype 转化 成 NullString Time + field.Set(reflect.New(fn)) + field = field.Elem() + log.Println("type:", fn.Name(), ",kind:", field.Kind(), ",fieldtype:", field.Type()) + } + + // log.Println(field.Kind(), field, reflect.TypeOf(field).Elem().Name(), columntype.ScanType().Kind()) + + if src == nil { + return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) + } + + switch columntype.DatabaseTypeName() { + + case "TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT": + isdefault, err := assign(field, src) + if err != nil { + return err + } + if isdefault { + s := asString(src) + i64, err := strconv.ParseInt(s, 10, 64) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, field.Kind(), err) + } + // reflect.New(reflect.TypeOf(i64)) + field.Set(reflect.ValueOf(i64)) + } + + case "FLOAT", "DOUBLE", "DECIMAL": + isdefault, err := assign(field, src) + if err != nil { + return err + } + if isdefault { + s := asString(src) + f64, err := strconv.ParseFloat(s, 64) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, field.Kind(), err) + } + field.Set(reflect.ValueOf(f64)) + } + + case "BINARY", "VARBINARY", "TINYBLOB", "BLOB", "MEDIUMBLOB", "LONGBLOB", "JSON": + isdefault, err := assign(field, src) + if err != nil { + return err + } + if isdefault { + field.Set(reflect.ValueOf(src.([]byte))) + } + case "CHAR", "VARCHAR", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT": + isdefault, err := assign(field, src) + if err != nil { + return err + } + if isdefault { + field.Set(reflect.ValueOf(string(src.([]byte)))) + } + + case "BIT": + var bits []byte = make([]byte, 8) + copy(bits, src.([]byte)) + + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + field.SetInt(int64(binary.LittleEndian.Uint64(bits))) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + field.SetUint(binary.LittleEndian.Uint64(bits)) + + case reflect.Interface: + field.Set(reflect.ValueOf(binary.LittleEndian.Uint64(bits))) + + } + + case "YEAR", "TIME", "DATE", "DATETIME", "TIMESTAMP": + s := src.(time.Time) + switch field.Interface().(type) { + case time.Time: + field.Set(reflect.ValueOf(src)) + case string: + field.SetString(s.Format(time.RFC3339Nano)) + case []byte: + field.SetBytes([]byte(s.Format(time.RFC3339Nano))) + default: + } + } + + // log.Println(fv, columntype.ScanType().Kind()) + + if iscan, ok := field.Addr().Interface().(sql.Scanner); ok { + err := iscan.Scan(src) + if err != nil { + return err + } + return nil + } + + return nil +} diff --git a/autostore_test.go b/autostore_test.go index 7e4a808..f670675 100644 --- a/autostore_test.go +++ b/autostore_test.go @@ -2,69 +2,16 @@ package intimate import ( "database/sql" - "encoding/binary" "encoding/json" "fmt" "log" "reflect" - "strconv" "testing" + "time" "github.com/davecgh/go-spew/spew" ) -type Store struct { - db *sql.DB -} - -type Table struct { - store *Store - name string - setting interface{} - - updatesql string - selectsql string - insertsql string -} - -// const updatesql = "UPDATE %s SET %s WHERE %s = ?" - -func NewStore(uri string) *Store { - db, err := sql.Open("mysql", uri) - if err != nil { - panic(err) - } - s := &Store{db: db} - return s -} - -func (store *Store) Table(name string) *Table { - table := &Table{store: store} - table.name = name - - table.insertsql = `INSERT INTO ` + table.name + `(%s) values(%s)` - table.updatesql = `UPDATE ` + table.name + ` SET %s WHERE %s = ?` - // table.selectsql = `FROM ` + table.name + `WHERE operator` - return table -} - -type Queue struct { - table *Table - obj reflect.Type - selected string - condition string - uidname string - uididx int -} - -type OperatorType string - -const ( - OP_OK OperatorType = "0" - OP_WAIT OperatorType = "1000" - OP_ERROR OperatorType = "10000" -) - func (queue *Queue) Pop() (result interface{}, err error) { db := queue.table.store.db @@ -113,7 +60,7 @@ func (queue *Queue) Pop() (result interface{}, err error) { return nil, err } - _, err = tx.Exec("UPDATE "+queue.table.name+" SET operator = "+string(OP_WAIT)+" WHERE "+queue.uidname+" = ?", fields[queue.uididx]) + _, err = tx.Exec("UPDATE "+queue.table.name+" SET operator = "+string(OpWAIT)+" WHERE "+queue.uidname+" = ?", fields[queue.uididx]) if err != nil { log.Println(err) return nil, err @@ -147,7 +94,7 @@ func TestAutoStore(t *testing.T) { streamer.Name = "streamer" streamer.Operator = 0 streamer.Bit = 0b11 - streamer.Ext = &sql.NullString{String: "ext", Valid: true} + // streamer.Ext = &sql.NullString{String: "ext", Valid: true} tag := make(map[string]interface{}) tag["json"] = true @@ -157,305 +104,22 @@ func TestAutoStore(t *testing.T) { t.Error(err) } streamer.Iface = btag + now := time.Now() + streamer.UpdateTime = &now err = store.Table("streamer").Insert(streamer) if err != nil { t.Error(err) } } -func assign(field reflect.Value, dest interface{}) (bool, error) { - switch field.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - - s := asString(dest) - i64, err := strconv.ParseInt(s, 10, field.Type().Bits()) - if err != nil { - err = strconvErr(err) - return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) - } - field.SetInt(i64) - return false, nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - - s := asString(dest) - u64, err := strconv.ParseUint(s, 10, field.Type().Bits()) - if err != nil { - err = strconvErr(err) - return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) - } - field.SetUint(u64) - return false, nil - case reflect.Float32, reflect.Float64: - s := asString(dest) - f64, err := strconv.ParseFloat(s, field.Type().Bits()) - if err != nil { - err = strconvErr(err) - return false, fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) - } - field.SetFloat(f64) - return false, nil - case reflect.String: - field.SetString(string(dest.([]byte))) - return false, nil - case reflect.Interface: - return true, nil - } - - return false, fmt.Errorf("") -} -func convert(dest interface{}, field reflect.Value, columntype *sql.ColumnType) error { - - log.Println("type:", field.Type(), ",kind:", field.Kind(), ",field:", field, "scanType:", columntype.ScanType(), "databaseType:", columntype.DatabaseTypeName()) - if field.Kind() == reflect.Ptr { - fn := field.Type().Elem() // New 一个 field.Type().Elem() . 然后判断 columntype 转化 成 NullString Time - field.Set(reflect.New(fn)) - field = field.Elem() - log.Println("type:", fn.Name(), ",kind:", field.Kind(), ",fieldtype:", field.Type()) - } - - // log.Println(field.Kind(), field, reflect.TypeOf(field).Elem().Name(), columntype.ScanType().Kind()) - - if dest == nil { - return fmt.Errorf("converting NULL to %s is unsupported", field.Kind()) - } - - switch columntype.DatabaseTypeName() { - case "TINYINT": - fallthrough - case "SMALLINT": - fallthrough - case "MEDIUMINT": - fallthrough - case "INT": - fallthrough - case "BIGINT": - - isdefault, err := assign(field, dest) - if err != nil { - return err - } - if isdefault { - s := asString(dest) - i64, err := strconv.ParseInt(s, 10, 64) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) - } - // reflect.New(reflect.TypeOf(i64)) - field.Set(reflect.ValueOf(i64)) - } - return nil - - case "FLOAT": - fallthrough - case "DOUBLE": - fallthrough - case "DECIMAL": - isdefault, err := assign(field, dest) - if err != nil { - return err - } - if isdefault { - s := asString(dest) - f64, err := strconv.ParseFloat(s, 64) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", dest, s, field.Kind(), err) - } - field.Set(reflect.ValueOf(f64)) - } - return nil - - case "BINARY": - fallthrough - case "VARBINARY": - fallthrough - case "TINYBLOB": - fallthrough - case "BLOB": - fallthrough - case "MEDIUMBLOB": - fallthrough - case "LONGBLOB": - fallthrough - case "JSON": - isdefault, err := assign(field, dest) - if err != nil { - return err - } - if isdefault { - field.Set(reflect.ValueOf(dest.([]byte))) - } - case "CHAR": - fallthrough - case "VARCHAR": - fallthrough - case "TINYTEXT": - fallthrough - case "TEXT": - fallthrough - case "MEDIUMTEXT": - fallthrough - case "LONGTEXT": - isdefault, err := assign(field, dest) - if err != nil { - return err - } - if isdefault { - field.Set(reflect.ValueOf(string(dest.([]byte)))) - } - return nil - case "BIT": - var bits []byte = make([]byte, 8) - copy(bits, dest.([]byte)) - switch field.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - field.SetInt(int64(binary.LittleEndian.Uint64(bits))) - return nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - field.SetUint(binary.LittleEndian.Uint64(bits)) - return nil - case reflect.Interface: - field.Set(reflect.ValueOf(binary.LittleEndian.Uint64(bits))) - return nil - } - - return nil - } - - // log.Println(fv, columntype.ScanType().Kind()) - - if iscan, ok := field.Addr().Interface().(sql.Scanner); ok { - err := iscan.Scan(dest) - if err != nil { - return err - } - return nil - } - - return nil -} - -func (t *Table) Queue(obj interface{}, whereCondition string) *Queue { - q := &Queue{} - q.condition = whereCondition - q.obj = reflect.TypeOf(obj) - q.table = t - - for i := 0; i < q.obj.NumField(); i++ { - field := q.obj.Field(i) - if fname, ok := field.Tag.Lookup("field"); ok { - q.selected += fname + "," - if _, ok := field.Tag.Lookup("uid"); ok { - q.uididx = i - q.uidname = fname - } - } - - } - - q.selected = q.selected[:len(q.selected)-1] - return q -} - -func (t *Table) Insert(obj interface{}) error { - ov := reflect.ValueOf(obj).Elem() - ot := reflect.TypeOf(obj) - - fieldsql := "" - argssql := "" - - var args []interface{} - for i := 0; i < ov.NumField(); i++ { - field := ov.Field(i) - ftype := ot.Elem().Field(i) - - if fname, ok := ftype.Tag.Lookup("field"); ok { - if flag, ok := ftype.Tag.Lookup("uid"); ok { - if flag == "auto" { - continue - } - } - - k := ftype.Type.Kind() - if k == reflect.Ptr || k == reflect.Interface { - if !field.IsNil() { - felem := field.Elem() - args = append(args, felem.Interface()) - fieldsql += fname + "," - argssql += "?," - } - } else { - args = append(args, field.Interface()) - fieldsql += fname + "," - argssql += "?," - } - - } - - } - - ssql := fmt.Sprintf(t.insertsql, fieldsql[:len(fieldsql)-1], argssql[:len(argssql)-1]) - _, err := t.store.db.Exec(ssql, args...) - return err -} - -func (t *Table) Update(obj interface{}) error { - - ov := reflect.ValueOf(obj).Elem() - ot := reflect.TypeOf(obj) - - fieldsql := "" - var uidname string - var uidvalue interface{} - - var args []interface{} - for i := 0; i < ov.NumField(); i++ { - field := ov.Field(i) - ftype := ot.Elem().Field(i) - - if fname, ok := ftype.Tag.Lookup("field"); ok { - if _, ok := ftype.Tag.Lookup("uid"); ok { - if uidvalue != nil { - panic(fmt.Errorf("uid must unique, %s and %s", uidname, fname)) - } - uidname = fname - uidvalue = field.Interface() - continue - } - - k := ftype.Type.Kind() - if k == reflect.Ptr || k == reflect.Interface { - if !field.IsNil() { - felem := field.Elem() - args = append(args, felem.Interface()) - fieldsql += fname + " = ?," - } - } else { - args = append(args, field.Interface()) - fieldsql += fname + " = ?," - } - - } - - } - - if uidvalue == nil { - panic(fmt.Errorf("update must contain `uid` tag")) - } - - usql := fmt.Sprintf(t.updatesql, fieldsql[:len(fieldsql)-1], uidname) - args = append(args, uidvalue) - _, err := t.store.db.Exec(usql, args...) - return err -} type TSreamer struct { - Uid int `field:"uid" uid:"auto"` - Name interface{} `field:"name"` - UserID *sql.NullString `field:"userid"` - Ext *sql.NullString `field:"ext"` - Iface interface{} `field:"tag"` - Bit uint64 `field:"bit"` - Operator int `field:"operator"` + Uid int `field:"uid" uid:"auto"` + Name interface{} `field:"name"` + UserID *sql.NullString `field:"userid"` + Ext *sql.NullString `field:"ext"` + Iface interface{} `field:"tag"` + Bit uint64 `field:"bit"` + Operator int `field:"operator"` + UpdateTime *time.Time `field:"update_time"` } From 7849d09a18296e718d4fd29ccbfd5d717e57f127 Mon Sep 17 00:00:00 2001 From: eson Date: Mon, 7 Sep 2020 17:13:40 +0800 Subject: [PATCH 12/18] =?UTF-8?q?=E5=AE=8C=E6=88=90autostore.=20TODO:=20?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2old=20store=20=E7=B1=BB.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autostore.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++ autostore_test.go | 68 +--------------------------------------------- 2 files changed, 70 insertions(+), 67 deletions(-) diff --git a/autostore.go b/autostore.go index 48c3f4f..a7a7e65 100644 --- a/autostore.go +++ b/autostore.go @@ -10,6 +10,8 @@ import ( "time" ) +/*Store 结构体. 必须使用tag. field 数据库字段标签 uid 唯一id字段标签必须存在 + */ type Store struct { db *sql.DB } @@ -35,6 +37,7 @@ func NewStore(uri string) *Store { return s } +// Table 选择表. func (store *Store) Table(name string) *Table { table := &Table{store: store} table.name = name @@ -42,9 +45,11 @@ func (store *Store) Table(name string) *Table { table.insertsql = `INSERT INTO ` + table.name + `(%s) values(%s)` table.updatesql = `UPDATE ` + table.name + ` SET %s WHERE %s = ?` // table.selectsql = `FROM ` + table.name + `WHERE operator` + table.selectsql = `SELECT %s FROM ` + table.name + ` WHERE %s ` return table } +// Queue mysql 队列结构 type Queue struct { table *Table obj reflect.Type @@ -66,6 +71,7 @@ const ( OpERROR OperatorType = "10000" ) +// Queue 根据Table生成一个队列. 处理结构. 每次弹出一个 obj 是要处理的结构体 自定义的whereCondition条件 func (t *Table) Queue(obj interface{}, whereCondition string) *Queue { q := &Queue{} q.condition = whereCondition @@ -88,6 +94,68 @@ func (t *Table) Queue(obj interface{}, whereCondition string) *Queue { return q } +// Pop 队列弹出一个数据(任务). 参考队列处理 不支持嵌套. +func (queue *Queue) Pop() (result interface{}, err error) { + + db := queue.table.store.db + tx, err := db.Begin() + if err != nil { + return nil, err + } + + defer func() { + cerr := tx.Commit() + if cerr != nil { + log.Println(cerr) + log.Println(tx.Rollback()) + } + }() + + selectsql := `SELECT ` + queue.selected + ` FROM ` + queue.table.name + ` WHERE ` + queue.condition + " limit 1 for update" + rows, err := tx.Query(selectsql) + + if err != nil { + return nil, fmt.Errorf("table: %s queue is empty", queue.table.name) + } + + var fields = make([]interface{}, queue.obj.NumField()) + for i := range fields { + var iv interface{} + fields[i] = &iv + } + + if rows.Next() { + err = rows.Scan(fields...) + if err != nil { + return nil, err + } + } + + columntypes, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + if err = rows.Close(); err != nil { + return nil, err + } + + _, err = tx.Exec("UPDATE "+queue.table.name+" SET operator = "+string(OpWAIT)+" WHERE "+queue.uidname+" = ?", fields[queue.uididx]) + if err != nil { + log.Println(err) + return nil, err + } + + obj := reflect.New(queue.obj).Elem() + for i := 0; i < obj.NumField(); i++ { + field := obj.Field(i) + convert(*fields[i].(*interface{}), field, columntypes[i]) + } + + return obj.Addr().Interface(), err +} + +// Insert nil 不插入. 不支持嵌套. func (t *Table) Insert(obj interface{}) error { ov := reflect.ValueOf(obj).Elem() ot := reflect.TypeOf(obj) @@ -130,6 +198,7 @@ func (t *Table) Insert(obj interface{}) error { return err } +// Update 结构体更新 func (t *Table) Update(obj interface{}) error { ov := reflect.ValueOf(obj).Elem() diff --git a/autostore_test.go b/autostore_test.go index f670675..d0aaae5 100644 --- a/autostore_test.go +++ b/autostore_test.go @@ -3,79 +3,13 @@ package intimate import ( "database/sql" "encoding/json" - "fmt" - "log" - "reflect" "testing" "time" "github.com/davecgh/go-spew/spew" ) -func (queue *Queue) Pop() (result interface{}, err error) { - - db := queue.table.store.db - tx, err := db.Begin() - if err != nil { - return nil, err - } - - defer func() { - cerr := tx.Commit() - if cerr != nil { - log.Println(cerr) - log.Println(tx.Rollback()) - } - }() - - selectsql := `SELECT ` + queue.selected + ` FROM ` + queue.table.name + ` WHERE ` + queue.condition + " limit 1 for update" - rows, err := tx.Query(selectsql) - // err = rows.Err() - if err != nil { - return nil, fmt.Errorf("table: %s queue is empty", queue.table.name) - } - - var fields = make([]interface{}, queue.obj.NumField()) - for i := range fields { - var iv interface{} - fields[i] = &iv - } - - // if !rows.Next() { - // return nil, fmt.Errorf("table: %s queue is empty", queue.table.name) - // } - if rows.Next() { - err = rows.Scan(fields...) - if err != nil { - return nil, err - } - } - - columntypes, err := rows.ColumnTypes() - if err != nil { - return nil, err - } - - if err = rows.Close(); err != nil { - return nil, err - } - - _, err = tx.Exec("UPDATE "+queue.table.name+" SET operator = "+string(OpWAIT)+" WHERE "+queue.uidname+" = ?", fields[queue.uididx]) - if err != nil { - log.Println(err) - return nil, err - } - - obj := reflect.New(queue.obj).Elem() - for i := 0; i < obj.NumField(); i++ { - field := obj.Field(i) - convert(*fields[i].(*interface{}), field, columntypes[i]) - } - - return obj.Addr().Interface(), err -} - -func TestAutoStore(t *testing.T) { +func estAutoStore(t *testing.T) { uri := "root:@tcp(127.0.0.1:4000)/test?parseTime=true&loc=Local&charset=utf8mb4&collation=utf8mb4_unicode_ci" store := NewStore(uri) From 2c557e3b42e9fb8c50475f46fde0cf323a5367b8 Mon Sep 17 00:00:00 2001 From: eson Date: Mon, 7 Sep 2020 18:12:18 +0800 Subject: [PATCH 13/18] =?UTF-8?q?todo:=20twitcasting=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=20store.=202.=20=E4=BF=AE=E6=94=B9streamer.=20tag=20=E7=AC=A6?= =?UTF-8?q?=E5=90=88=E8=A6=81=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autostore.go | 18 +- config.go | 12 + convert.go | 452 +++++++++--------- tasks/nimo/nimo_task1/nimo_task1.go | 2 +- tasks/openrec/openrec_task2/task_openrec.go | 10 - .../twitcasting_task1/main_test.go | 2 +- .../twitcasting_task1/twitcasting.go | 4 +- 7 files changed, 256 insertions(+), 244 deletions(-) diff --git a/autostore.go b/autostore.go index a7a7e65..4f061be 100644 --- a/autostore.go +++ b/autostore.go @@ -10,6 +10,18 @@ import ( "time" ) +// StoreExtractorDB 全局的Extractor DB 库链接 +var StoreExtractorDB *Store + +// TStreamer 全局的Streamer. 在config init 完成初始化 +var TStreamer *Table + +// TClog 全局的Clog +var TClog *Table + +// TStreamerList 全局的streamer list 这个表存的url. 进去可以找到主播的列表. 便于动态更新 +var TStreamerList *Table + /*Store 结构体. 必须使用tag. field 数据库字段标签 uid 唯一id字段标签必须存在 */ type Store struct { @@ -287,12 +299,12 @@ func assign(field reflect.Value, src interface{}) (bool, error) { func convert(src interface{}, field reflect.Value, columntype *sql.ColumnType) error { - log.Println("type:", field.Type(), ",kind:", field.Kind(), ",field:", field, "scanType:", columntype.ScanType(), "databaseType:", columntype.DatabaseTypeName()) + // log.Println("type:", field.Type(), ",kind:", field.Kind(), ",field:", field, "scanType:", columntype.ScanType(), "databaseType:", columntype.DatabaseTypeName()) if field.Kind() == reflect.Ptr { fn := field.Type().Elem() // New 一个 field.Type().Elem() . 然后判断 columntype 转化 成 NullString Time field.Set(reflect.New(fn)) field = field.Elem() - log.Println("type:", fn.Name(), ",kind:", field.Kind(), ",fieldtype:", field.Type()) + // log.Println("type:", fn.Name(), ",kind:", field.Kind(), ",fieldtype:", field.Type()) } // log.Println(field.Kind(), field, reflect.TypeOf(field).Elem().Name(), columntype.ScanType().Kind()) @@ -302,7 +314,6 @@ func convert(src interface{}, field reflect.Value, columntype *sql.ColumnType) e } switch columntype.DatabaseTypeName() { - case "TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT": isdefault, err := assign(field, src) if err != nil { @@ -387,7 +398,6 @@ func convert(src interface{}, field reflect.Value, columntype *sql.ColumnType) e if err != nil { return err } - return nil } return nil diff --git a/config.go b/config.go index 369ca21..547c5dc 100644 --- a/config.go +++ b/config.go @@ -18,6 +18,18 @@ func init() { // storeOpenrec = NewStore() log.SetFlags(log.Llongfile | log.Ltime) + + // StoreExtractorDB 全局的Extractor DB 库链接 + StoreExtractorDB = NewStore(InitConfig.Database.ExtractorURI) + + // TStreamer 全局的Streamer + TStreamer = StoreExtractorDB.Table("streamer") + + // TClog 全局的Clog + TClog = StoreExtractorDB.Table("collect_log") + + // TStreamerList 全局的streamer list 这个表存的url. 进去可以找到主播的列表. 便于动态更新 + TStreamerList = StoreExtractorDB.Table("streamer_list") } // Config 配置 diff --git a/convert.go b/convert.go index 4e8d149..23bea55 100644 --- a/convert.go +++ b/convert.go @@ -7,13 +7,11 @@ package intimate import ( - "database/sql" "database/sql/driver" "errors" "fmt" "reflect" "strconv" - "time" ) var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error @@ -23,240 +21,240 @@ var errNilPtr = errors.New("destination pointer is nil") // embedded in descript // dest should be a pointer type. If rows is passed in, the rows will // be used as the parent for any cursor values converted from a // driver.Rows to a *Rows. -func convertAssignRows(dest, src interface{}, rows *sql.Rows) error { - // Common cases, without reflect. - switch s := src.(type) { - case string: - switch d := dest.(type) { - case *string: - if d == nil { - return errNilPtr - } - *d = s - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = []byte(s) - return nil - case *sql.RawBytes: - if d == nil { - return errNilPtr - } - *d = append((*d)[:0], s...) - return nil - } - case []byte: - switch d := dest.(type) { - case *string: - if d == nil { - return errNilPtr - } - *d = string(s) - return nil - case *interface{}: - if d == nil { - return errNilPtr - } - *d = cloneBytes(s) - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = cloneBytes(s) - return nil - case *sql.RawBytes: - if d == nil { - return errNilPtr - } - *d = s - return nil - } - case time.Time: - switch d := dest.(type) { - case *time.Time: - *d = s - return nil - case *string: - *d = s.Format(time.RFC3339Nano) - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = []byte(s.Format(time.RFC3339Nano)) - return nil - case *sql.RawBytes: - if d == nil { - return errNilPtr - } - *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) - return nil - } - case decimalDecompose: - switch d := dest.(type) { - case decimalCompose: - return d.Compose(s.Decompose(nil)) - } - case nil: - switch d := dest.(type) { - case *interface{}: - if d == nil { - return errNilPtr - } - *d = nil - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = nil - return nil - case *sql.RawBytes: - if d == nil { - return errNilPtr - } - *d = nil - return nil - } - // The driver is returning a cursor the client may iterate over. - } +// func convertAssignRows(dest, src interface{}, rows *sql.Rows) error { +// // Common cases, without reflect. +// switch s := src.(type) { +// case string: +// switch d := dest.(type) { +// case *string: +// if d == nil { +// return errNilPtr +// } +// *d = s +// return nil +// case *[]byte: +// if d == nil { +// return errNilPtr +// } +// *d = []byte(s) +// return nil +// case *sql.RawBytes: +// if d == nil { +// return errNilPtr +// } +// *d = append((*d)[:0], s...) +// return nil +// } +// case []byte: +// switch d := dest.(type) { +// case *string: +// if d == nil { +// return errNilPtr +// } +// *d = string(s) +// return nil +// case *interface{}: +// if d == nil { +// return errNilPtr +// } +// *d = cloneBytes(s) +// return nil +// case *[]byte: +// if d == nil { +// return errNilPtr +// } +// *d = cloneBytes(s) +// return nil +// case *sql.RawBytes: +// if d == nil { +// return errNilPtr +// } +// *d = s +// return nil +// } +// case time.Time: +// switch d := dest.(type) { +// case *time.Time: +// *d = s +// return nil +// case *string: +// *d = s.Format(time.RFC3339Nano) +// return nil +// case *[]byte: +// if d == nil { +// return errNilPtr +// } +// *d = []byte(s.Format(time.RFC3339Nano)) +// return nil +// case *sql.RawBytes: +// if d == nil { +// return errNilPtr +// } +// *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) +// return nil +// } +// case decimalDecompose: +// switch d := dest.(type) { +// case decimalCompose: +// return d.Compose(s.Decompose(nil)) +// } +// case nil: +// switch d := dest.(type) { +// case *interface{}: +// if d == nil { +// return errNilPtr +// } +// *d = nil +// return nil +// case *[]byte: +// if d == nil { +// return errNilPtr +// } +// *d = nil +// return nil +// case *sql.RawBytes: +// if d == nil { +// return errNilPtr +// } +// *d = nil +// return nil +// } +// // The driver is returning a cursor the client may iterate over. +// } - var sv reflect.Value +// var sv reflect.Value - switch d := dest.(type) { - case *string: - sv = reflect.ValueOf(src) - switch sv.Kind() { - case reflect.Bool, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Float32, reflect.Float64: - *d = asString(src) - return nil - } - case *[]byte: - sv = reflect.ValueOf(src) - if b, ok := asBytes(nil, sv); ok { - *d = b - return nil - } - case *sql.RawBytes: - sv = reflect.ValueOf(src) - if b, ok := asBytes([]byte(*d)[:0], sv); ok { - *d = sql.RawBytes(b) - return nil - } - case *bool: - bv, err := driver.Bool.ConvertValue(src) - if err == nil { - *d = bv.(bool) - } - return err - case *interface{}: - *d = src - return nil - } +// switch d := dest.(type) { +// case *string: +// sv = reflect.ValueOf(src) +// switch sv.Kind() { +// case reflect.Bool, +// reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, +// reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, +// reflect.Float32, reflect.Float64: +// *d = asString(src) +// return nil +// } +// case *[]byte: +// sv = reflect.ValueOf(src) +// if b, ok := asBytes(nil, sv); ok { +// *d = b +// return nil +// } +// case *sql.RawBytes: +// sv = reflect.ValueOf(src) +// if b, ok := asBytes([]byte(*d)[:0], sv); ok { +// *d = sql.RawBytes(b) +// return nil +// } +// case *bool: +// bv, err := driver.Bool.ConvertValue(src) +// if err == nil { +// *d = bv.(bool) +// } +// return err +// case *interface{}: +// *d = src +// return nil +// } - if scanner, ok := dest.(sql.Scanner); ok { - return scanner.Scan(src) - } +// if scanner, ok := dest.(sql.Scanner); ok { +// return scanner.Scan(src) +// } - dpv := reflect.ValueOf(dest) - if dpv.Kind() != reflect.Ptr { - return errors.New("destination not a pointer") - } - if dpv.IsNil() { - return errNilPtr - } +// dpv := reflect.ValueOf(dest) +// if dpv.Kind() != reflect.Ptr { +// return errors.New("destination not a pointer") +// } +// if dpv.IsNil() { +// return errNilPtr +// } - if !sv.IsValid() { - sv = reflect.ValueOf(src) - } +// if !sv.IsValid() { +// sv = reflect.ValueOf(src) +// } - dv := reflect.Indirect(dpv) - if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { - switch b := src.(type) { - case []byte: - dv.Set(reflect.ValueOf(cloneBytes(b))) - default: - dv.Set(sv) - } - return nil - } +// dv := reflect.Indirect(dpv) +// if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { +// switch b := src.(type) { +// case []byte: +// dv.Set(reflect.ValueOf(cloneBytes(b))) +// default: +// dv.Set(sv) +// } +// return nil +// } - if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { - dv.Set(sv.Convert(dv.Type())) - return nil - } +// if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { +// dv.Set(sv.Convert(dv.Type())) +// return nil +// } - // The following conversions use a string value as an intermediate representation - // to convert between various numeric types. - // - // This also allows scanning into user defined types such as "type Int int64". - // For symmetry, also check for string destination types. - switch dv.Kind() { - case reflect.Ptr: - if src == nil { - dv.Set(reflect.Zero(dv.Type())) - return nil - } - dv.Set(reflect.New(dv.Type().Elem())) - return convertAssignRows(dv.Interface(), src, rows) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if src == nil { - return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) - } - s := asString(src) - i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) - } - dv.SetInt(i64) - return nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - if src == nil { - return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) - } - s := asString(src) - u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) - } - dv.SetUint(u64) - return nil - case reflect.Float32, reflect.Float64: - if src == nil { - return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) - } - s := asString(src) - f64, err := strconv.ParseFloat(s, dv.Type().Bits()) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) - } - dv.SetFloat(f64) - return nil - case reflect.String: - if src == nil { - return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) - } - switch v := src.(type) { - case string: - dv.SetString(v) - return nil - case []byte: - dv.SetString(string(v)) - return nil - } - } +// // The following conversions use a string value as an intermediate representation +// // to convert between various numeric types. +// // +// // This also allows scanning into user defined types such as "type Int int64". +// // For symmetry, also check for string destination types. +// switch dv.Kind() { +// case reflect.Ptr: +// if src == nil { +// dv.Set(reflect.Zero(dv.Type())) +// return nil +// } +// dv.Set(reflect.New(dv.Type().Elem())) +// return convertAssignRows(dv.Interface(), src, rows) +// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: +// if src == nil { +// return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) +// } +// s := asString(src) +// i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) +// if err != nil { +// err = strconvErr(err) +// return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) +// } +// dv.SetInt(i64) +// return nil +// case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: +// if src == nil { +// return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) +// } +// s := asString(src) +// u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) +// if err != nil { +// err = strconvErr(err) +// return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) +// } +// dv.SetUint(u64) +// return nil +// case reflect.Float32, reflect.Float64: +// if src == nil { +// return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) +// } +// s := asString(src) +// f64, err := strconv.ParseFloat(s, dv.Type().Bits()) +// if err != nil { +// err = strconvErr(err) +// return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) +// } +// dv.SetFloat(f64) +// return nil +// case reflect.String: +// if src == nil { +// return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) +// } +// switch v := src.(type) { +// case string: +// dv.SetString(v) +// return nil +// case []byte: +// dv.SetString(string(v)) +// return nil +// } +// } - return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) -} +// return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) +// } func strconvErr(err error) error { if ne, ok := err.(*strconv.NumError); ok { diff --git a/tasks/nimo/nimo_task1/nimo_task1.go b/tasks/nimo/nimo_task1/nimo_task1.go index 827e0bf..96281a3 100644 --- a/tasks/nimo/nimo_task1/nimo_task1.go +++ b/tasks/nimo/nimo_task1/nimo_task1.go @@ -95,8 +95,8 @@ func Execute() { } streamer.UpdateInterval = 120 - // spew.Println(streamer) estore.InsertStreamer(streamer) + } else { log.Println("userid is null.", room.String()) } diff --git a/tasks/openrec/openrec_task2/task_openrec.go b/tasks/openrec/openrec_task2/task_openrec.go index c88fa6f..abfad26 100644 --- a/tasks/openrec/openrec_task2/task_openrec.go +++ b/tasks/openrec/openrec_task2/task_openrec.go @@ -111,16 +111,6 @@ func Execute() { supporters = append(supporters, string(resp.Content())) temporary.QueryParam("page_number").IntAdd(1) - // page := supportersQuery.Get("page_number") // page_number 加1 - // pageint, err := strconv.Atoi(page) - // if err != nil { - // log.Println(err) - // break - // } - // pageint++ - // page = strconv.Itoa(pageint) - // supportersQuery.Set("page_number", page) - // temporary.SetQuery(supportersQuery) } // cookies := cxt.Session().GetCookies(wf.GetParsedURL()) diff --git a/tasks/twitcasting/twitcasting_task1/main_test.go b/tasks/twitcasting/twitcasting_task1/main_test.go index 18bfb6a..f856c03 100644 --- a/tasks/twitcasting/twitcasting_task1/main_test.go +++ b/tasks/twitcasting/twitcasting_task1/main_test.go @@ -21,5 +21,5 @@ func TestUpdateTime(t *testing.T) { } func TestMain(t *testing.T) { - + main() } diff --git a/tasks/twitcasting/twitcasting_task1/twitcasting.go b/tasks/twitcasting/twitcasting_task1/twitcasting.go index a11e724..e8a133a 100644 --- a/tasks/twitcasting/twitcasting_task1/twitcasting.go +++ b/tasks/twitcasting/twitcasting_task1/twitcasting.go @@ -132,7 +132,9 @@ func Execute() { streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} streamer.UserName = sql.NullString{String: sp.UserName, Valid: true} streamer.UserId = sp.UserId - estore.InsertStreamer(streamer) + streamer.Operator = 33 + // estore.InsertStreamer(streamer) + intimate.TStreamer.Insert(streamer) } log.Println("finish remain", queue.Size()) From 28319bf02af66c784910530de49cd68958e3e071 Mon Sep 17 00:00:00 2001 From: eson Date: Mon, 7 Sep 2020 18:52:59 +0800 Subject: [PATCH 14/18] TODO --- extractor_field.go | 24 +++++++++---------- store.go | 2 +- .../twitcasting_task1/twitcasting.go | 10 ++++---- utils.go | 6 +++++ 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/extractor_field.go b/extractor_field.go index 91a6f4a..d4266da 100644 --- a/extractor_field.go +++ b/extractor_field.go @@ -40,23 +40,23 @@ func (sl *StreamerList) Set(field string, value interface{}) { type Streamer struct { Uid int64 `field:"uid" uid:"auto"` // Platform Platform `field:"platform"` // - UserId string // + UserId *string `field:"user_id"` // - UserName sql.NullString // - LiveUrl sql.NullString // - Channel sql.NullString // - Tags interface{} - Ext interface{} // + UserName *sql.NullString `field:"user_name"` // + LiveUrl *sql.NullString `field:"live_url"` // + Channel *sql.NullString `field:"channel"` // + Tags interface{} `field:"tags"` + Ext interface{} `field:"ext"` // IsUpdateStreamer bool // 更新上面的内容 IsUpdateUrl bool - UpdateInterval int32 - UpdateUrl interface{} - LatestLogUid int64 - UpdateTime sql.NullTime // + UpdateInterval int32 `field:"update_interval"` + UpdateUrl interface{} `field:"update_url"` + LatestLogUid int64 `field:"latest_log_uid"` + UpdateTime *sql.NullTime `field:"update_time"` // - ErrorMsg sql.NullString - Operator int32 + ErrorMsg *sql.NullString `field:"error_msg"` + Operator int32 `field:"operator"` LastOperator int32 } diff --git a/store.go b/store.go index 673bb81..a3179dd 100644 --- a/store.go +++ b/store.go @@ -379,7 +379,7 @@ func (store *StoreExtractor) InsertStreamer(streamer *Streamer) (isExists bool) } }() - streamer.UpdateTime = sql.NullTime{Time: time.Now().Add(-time.Hour * 100000), Valid: true} + streamer.UpdateTime = &sql.NullTime{Time: time.Now().Add(-time.Hour * 100000), Valid: true} _, err = tx.Exec("INSERT IGNORE INTO "+StreamerTable+"(platform, user_id, user_name, live_url, update_url, tags, update_time) VALUES(?,?,?,?,?,?,?);", streamer.Platform, streamer.UserId, diff --git a/tasks/twitcasting/twitcasting_task1/twitcasting.go b/tasks/twitcasting/twitcasting_task1/twitcasting.go index e8a133a..dbd5bdf 100644 --- a/tasks/twitcasting/twitcasting_task1/twitcasting.go +++ b/tasks/twitcasting/twitcasting_task1/twitcasting.go @@ -122,17 +122,17 @@ func Execute() { // log.Println(sp) streamer := &intimate.Streamer{} streamer.Platform = intimate.Ptwitcasting - streamer.LiveUrl = sql.NullString{String: sp.LiveUrl, Valid: true} + streamer.LiveUrl = &sql.NullString{String: sp.LiveUrl, Valid: true} if btags, err := json.Marshal(sp.Tag); err != nil { log.Println(err) } else { streamer.Tags = btags } streamer.UpdateInterval = 120 - streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} - streamer.UserName = sql.NullString{String: sp.UserName, Valid: true} - streamer.UserId = sp.UserId - streamer.Operator = 33 + streamer.UpdateTime = intimate.GetUpdateTimeNow() + streamer.UserName = &sql.NullString{String: sp.UserName, Valid: true} + streamer.UserId = &sp.UserId + streamer.Operator = 0 // estore.InsertStreamer(streamer) intimate.TStreamer.Insert(streamer) } diff --git a/utils.go b/utils.go index fda2b83..6bf7713 100644 --- a/utils.go +++ b/utils.go @@ -1,6 +1,7 @@ package intimate import ( + "database/sql" "fmt" "log" "os" @@ -28,6 +29,11 @@ func init() { } +// GetUpdateTimeNow 获取马上更新时间. 与第一次连用 +func GetUpdateTimeNow() *sql.NullTime { + return &sql.NullTime{Time: time.Now().Add(-time.Hour * 100000), Valid: true} +} + // ParseNumber 去逗号解析数字 func ParseNumber(num string) (int64, error) { num = strings.Trim(num, " ") From fb07d61353c0d3b1ca0490b603588b240536dfd8 Mon Sep 17 00:00:00 2001 From: eson Date: Tue, 8 Sep 2020 18:24:51 +0800 Subject: [PATCH 15/18] =?UTF-8?q?TODO:=20twitch=5Ftask2=20fix=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autostore.go | 129 +++++++- autostore_test.go | 2 +- .../openrec_extractor/openrec_extractor.go | 306 ++++++++++++------ .../twitcasting_extractor.go | 62 ++-- extractor_field.go | 55 ++-- tasks/nimo/nimo_task1/nimo_task1.go | 8 +- tasks/openrec/openrec_task1/task_openrec.go | 15 +- tasks/openrec/openrec_task2/.gitignore | 2 - tasks/openrec/openrec_task2/main.go | 5 - tasks/openrec/openrec_task2/task_openrec.go | 154 --------- .../openrec_task2/task_openrec_test.go | 9 - .../twitcasting_task1/twitcasting.go | 7 +- tasks/twitch/twitch_task1/task_twitch.go | 169 +++++----- utils.go | 5 + 14 files changed, 495 insertions(+), 433 deletions(-) delete mode 100644 tasks/openrec/openrec_task2/.gitignore delete mode 100644 tasks/openrec/openrec_task2/main.go delete mode 100644 tasks/openrec/openrec_task2/task_openrec.go delete mode 100644 tasks/openrec/openrec_task2/task_openrec_test.go diff --git a/autostore.go b/autostore.go index 4f061be..e3c6976 100644 --- a/autostore.go +++ b/autostore.go @@ -28,6 +28,7 @@ type Store struct { db *sql.DB } +// Table 表 type Table struct { store *Store name string @@ -38,8 +39,6 @@ type Table struct { insertsql string } -// const updatesql = "UPDATE %s SET %s WHERE %s = ?" - func NewStore(uri string) *Store { db, err := sql.Open("mysql", uri) if err != nil { @@ -56,19 +55,26 @@ func (store *Store) Table(name string) *Table { table.insertsql = `INSERT INTO ` + table.name + `(%s) values(%s)` table.updatesql = `UPDATE ` + table.name + ` SET %s WHERE %s = ?` - // table.selectsql = `FROM ` + table.name + `WHERE operator` table.selectsql = `SELECT %s FROM ` + table.name + ` WHERE %s ` return table } // Queue mysql 队列结构 type Queue struct { - table *Table - obj reflect.Type - selected string - condition string - uidname string - uididx int + table *Table + obj reflect.Type + fieldIndex []int + selected string + + cond CondWhere + + uidname string + uididx int +} + +type CondWhere struct { + Condition string + CondArgs []interface{} } // OperatorType 字典Operator 标志位的类型 @@ -83,12 +89,21 @@ const ( OpERROR OperatorType = "10000" ) +// ConditionDefault 默认的条件 +func ConditionDefault(platform Platform) CondWhere { + return CondWhere{ + Condition: "platform = ? and operator = 0 and TIMESTAMPDIFF(MINUTE , update_time, CURRENT_TIMESTAMP()) >= update_interval", + CondArgs: []interface{}{string(platform)}, + } +} + // Queue 根据Table生成一个队列. 处理结构. 每次弹出一个 obj 是要处理的结构体 自定义的whereCondition条件 -func (t *Table) Queue(obj interface{}, whereCondition string) *Queue { +func (t *Table) Queue(obj interface{}, whereCondition CondWhere) *Queue { q := &Queue{} - q.condition = whereCondition + q.cond = whereCondition q.obj = reflect.TypeOf(obj) q.table = t + q.fieldIndex = []int{} // select 需要配对字段变量的对应index位置 for i := 0; i < q.obj.NumField(); i++ { field := q.obj.Field(i) @@ -98,6 +113,7 @@ func (t *Table) Queue(obj interface{}, whereCondition string) *Queue { q.uididx = i q.uidname = fname } + q.fieldIndex = append(q.fieldIndex, i) } } @@ -123,14 +139,14 @@ func (queue *Queue) Pop() (result interface{}, err error) { } }() - selectsql := `SELECT ` + queue.selected + ` FROM ` + queue.table.name + ` WHERE ` + queue.condition + " limit 1 for update" - rows, err := tx.Query(selectsql) + selectsql := `SELECT ` + queue.selected + ` FROM ` + queue.table.name + ` WHERE ` + queue.cond.Condition + " limit 1 for update" + rows, err := tx.Query(selectsql, queue.cond.CondArgs...) if err != nil { return nil, fmt.Errorf("table: %s queue is empty", queue.table.name) } - var fields = make([]interface{}, queue.obj.NumField()) + var fields = make([]interface{}, len(queue.fieldIndex)) for i := range fields { var iv interface{} fields[i] = &iv @@ -159,15 +175,15 @@ func (queue *Queue) Pop() (result interface{}, err error) { } obj := reflect.New(queue.obj).Elem() - for i := 0; i < obj.NumField(); i++ { - field := obj.Field(i) + for i, idx := range queue.fieldIndex { + field := obj.Field(idx) convert(*fields[i].(*interface{}), field, columntypes[i]) } return obj.Addr().Interface(), err } -// Insert nil 不插入. 不支持嵌套. +// Insert nil 不插入. 不支持嵌套. 必须是Ptr类型 func (t *Table) Insert(obj interface{}) error { ov := reflect.ValueOf(obj).Elem() ot := reflect.TypeOf(obj) @@ -210,6 +226,52 @@ func (t *Table) Insert(obj interface{}) error { return err } +// InsertRetAutoID nil 不插入. 不支持嵌套. 并返回auto uid +func (t *Table) InsertRetAutoID(obj interface{}) (int64, error) { + ov := reflect.ValueOf(obj).Elem() + ot := reflect.TypeOf(obj) + + fieldsql := "" + argssql := "" + + var args []interface{} + for i := 0; i < ov.NumField(); i++ { + field := ov.Field(i) + ftype := ot.Elem().Field(i) + + if fname, ok := ftype.Tag.Lookup("field"); ok { + if flag, ok := ftype.Tag.Lookup("uid"); ok { + if flag == "auto" { + continue + } + } + + k := ftype.Type.Kind() + if k == reflect.Ptr || k == reflect.Interface { + if !field.IsNil() { + felem := field.Elem() + args = append(args, felem.Interface()) + fieldsql += fname + "," + argssql += "?," + } + } else { + args = append(args, field.Interface()) + fieldsql += fname + "," + argssql += "?," + } + + } + + } + + ssql := fmt.Sprintf(t.insertsql, fieldsql[:len(fieldsql)-1], argssql[:len(argssql)-1]) + result, err := t.store.db.Exec(ssql, args...) + if err != nil { + return 0, err + } + return result.LastInsertId() +} + // Update 结构体更新 func (t *Table) Update(obj interface{}) error { @@ -261,7 +323,40 @@ func (t *Table) Update(obj interface{}) error { return err } +// UpdateError 更新错误数据 +func (t *Table) UpdateError(obj interface{}, err error) { + + ov := reflect.ValueOf(obj).Elem() + ot := reflect.TypeOf(obj) + + var uidname string + var uidvalue interface{} + + for i := 0; i < ov.NumField(); i++ { + field := ov.Field(i) + ftype := ot.Elem().Field(i) + + if fname, ok := ftype.Tag.Lookup("field"); ok { + if _, ok := ftype.Tag.Lookup("uid"); ok { + if uidvalue != nil { + panic(fmt.Errorf("uid must unique, %s and %s", uidname, fname)) + } + uidname = fname + uidvalue = field.Interface() + break + } + } + } + + _, dberr := t.store.db.Exec("update "+t.name+" set operator = ?, error_msg = ? where ? = ?", 10000, sql.NullString{String: err.Error(), Valid: true}, uidname, uidvalue) + if dberr != nil { + // email tell owner to deal with + panic(err) + } +} + func assign(field reflect.Value, src interface{}) (bool, error) { + switch field.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: s := asString(src) diff --git a/autostore_test.go b/autostore_test.go index d0aaae5..e5a452b 100644 --- a/autostore_test.go +++ b/autostore_test.go @@ -13,7 +13,7 @@ func estAutoStore(t *testing.T) { uri := "root:@tcp(127.0.0.1:4000)/test?parseTime=true&loc=Local&charset=utf8mb4&collation=utf8mb4_unicode_ci" store := NewStore(uri) - queue := store.Table("streamer").Queue(TSreamer{}, "operator = 0") + queue := store.Table("streamer").Queue(TSreamer{}, CondWhere{Condition: "operator = 0"}) re, _ := queue.Pop() pstreamer := re.(*TSreamer) diff --git a/extractor/openrec_extractor/openrec_extractor.go b/extractor/openrec_extractor/openrec_extractor.go index b0c37d9..245c961 100644 --- a/extractor/openrec_extractor/openrec_extractor.go +++ b/extractor/openrec_extractor/openrec_extractor.go @@ -9,12 +9,11 @@ import ( "time" "github.com/474420502/extractor" + "github.com/474420502/gcurl" + "github.com/474420502/requests" "github.com/tidwall/gjson" ) -var estore = intimate.NewStoreExtractor() -var sstore = intimate.NewStoreSource(string(intimate.STOpenrec)) - //UserInfo 提取信息的结构体 type UserInfo struct { UserName string `exp:"//p[ contains(@class, 'c-global__user__profile__list__name__text')]"` @@ -34,135 +33,230 @@ type UserLive struct { func Execute() { ps := intimate.NewPerfectShutdown() + ses := requests.NewSession() + squeue := intimate.TStreamer.Queue(intimate.Streamer{}, intimate.ConditionDefault(intimate.Popenrec)) var lasterr error = nil for !ps.IsClose() { - var err error + istreamer, err := squeue.Pop() - source, err := sstore.Pop(intimate.TOpenrecUser, 0) - if err != nil { + // streamer, err := estore.Pop(intimate.Popenrec) //队列里弹出一个streamer行. 进行解析 + + if istreamer == nil || err != nil { if err != lasterr { log.Println(err, lasterr) lasterr = err } - time.Sleep(time.Second * 5) + time.Sleep(time.Second * 2) continue } - lasterr = nil + streamer := istreamer.(*intimate.Streamer) - sdata := source.Ext.([]byte) - datamap := gjson.ParseBytes(sdata).Map() + userId := *streamer.UserId - source.Operator = int32(intimate.OperatorError) - userId := datamap["var_user_id"].String() + var updateUrl map[string]string + err = json.Unmarshal(streamer.UpdateUrl.([]byte), &updateUrl) // 反序列化update_url, 里面存了需要采集的url + if err != nil { + log.Println(err) + continue + } + // Check Userid - streamer := &intimate.Streamer{} - streamer.UserId = userId - // streamer.Platform = intimate.Popenrec 不需要更新字段 + userUrl := updateUrl["user"] + log.Println(userUrl) + tp := ses.Get(userUrl) // 获取user url页面数据 + resp, err := tp.Execute() + streamer.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} - htmlUser := datamap["html_user"] - - userEtor := extractor.ExtractHtmlString(htmlUser.String()) - ui, ok1 := userEtor.GetObjectByTag(UserInfo{}).(*UserInfo) - - htmlLive := datamap["html_live"] - - liveEtor := extractor.ExtractHtmlString(htmlLive.String()) - ul, ok2 := liveEtor.GetObjectByTag(UserLive{}).(*UserLive) - - jsonSupporters := datamap["json_supporters"] - clog := &intimate.CollectLog{} - - if ok1 { - clog.Followers = sql.NullInt64{Int64: ui.Followers, Valid: true} - clog.Views = sql.NullInt64{Int64: ui.Views, Valid: true} - if ui.Views != 0 { - clog.IsLiveStreaming = true - } - streamer.UserName = sql.NullString{String: ui.UserName, Valid: true} - - giverjson := jsonSupporters - var givers []interface{} - var gratuity int64 = 0 - - for _, v := range giverjson.Array() { - giverSource := gjson.Parse(v.String()) - for _, item := range giverSource.Get("data.items").Array() { - givers = append(givers, item.Map()) - gratuity += item.Get("total_yells").Int() - } - } - - giversbytes, err := json.Marshal(givers) - if err != nil { - log.Println(err) - clog.ErrorMsg = sql.NullString{String: err.Error(), Valid: true} - } else { - clog.Giver = giversbytes - } - - clog.Gratuity = sql.NullInt64{Int64: gratuity, Valid: true} - } else { - log.Println("UserInfo may be not exists") - estore.UpdateError(streamer, errors.New("UserInfo may be not exists")) + if err != nil { + log.Println(err) + intimate.TStreamer.UpdateError(streamer, err) continue } - //log.Println(ul) - if ok2 { - clog.LiveTitle = sql.NullString{String: ul.Title, Valid: true} + cookies := ses.GetCookies(tp.GetParsedURL()) - startTime, err := time.ParseInLocation("2006-01-02T15:04:05Z07:00", ul.LiveStartTime, time.Local) - if err != nil { - log.Println(err) - } else { - clog.LiveStartTime = sql.NullTime{Time: startTime.Local(), Valid: true} - duration, err := intimate.ParseDuration(ul.LiveEndTime) - if err != nil { - log.Println(err) - } else { - endTime := startTime.Add(duration) - clog.LiveStartTime = sql.NullTime{Time: endTime.Local(), Valid: true} + scurl := updateUrl["supporters"] //获取打赏者的数据 + curl := gcurl.Parse(scurl) + supportersSession := curl.CreateSession() + + temporary := curl.CreateTemporary(supportersSession) + supportersSession.SetCookies(temporary.GetParsedURL(), cookies) + var supporters []string + for { // supporters 数据需要登录信息. 下面为赋值 supporters链接获取的uid token random码 + + supportersQuery := temporary.GetQuery() + + for _, cookie := range cookies { + if cookie.Name == "uuid" { + supportersQuery.Set("Uuid", cookie.Value) + continue + } + + if cookie.Name == "token" { + supportersQuery.Set("Token", cookie.Value) + continue + } + + if cookie.Name == "random" { + supportersQuery.Set("Random", cookie.Value) + continue } } - if tags, err := json.Marshal(ul.Tags); err == nil { - clog.Tags = tags - } else { - log.Println("json error", ul.Tags, clog.Tags) + supportersQuery.Set("identify_id", userId) + temporary.SetQuery(supportersQuery) + + resp, err := temporary.Execute() + if err != nil { + log.Println(err) } + supporterjson := gjson.ParseBytes(resp.Content()) + supporterdata := supporterjson.Get("data") //解析supporters获取的json数据 + if supporterdata.Type == gjson.Null { + break + } + supporters = append(supporters, string(resp.Content())) + + temporary.QueryParam("page_number").IntAdd(1) } - streamer.Uid = source.StreamerId.Int64 - streamer.UpdateTime = source.UpdateTime - if clog.Tags != nil { - streamer.Tags = clog.Tags + // cookies := cxt.Session().GetCookies(wf.GetParsedURL()) + // ext := make(map[string]interface{}) + + jsonSupporters := supporters + htmlUser := string(resp.Content()) + + liveUrl := updateUrl["live"] + tp = ses.Get(liveUrl) + resp, err = tp.Execute() + if err != nil { + log.Println(err) + intimate.TStreamer.UpdateError(streamer, err) + continue } - clog.Platform = intimate.Popenrec - clog.UserId = userId - clog.UpdateTime = source.UpdateTime - clog.StreamerUid = streamer.Uid + htmlLive := string(resp.Content()) + // ext["var_user_id"] = userId - logUid := estore.InsertClog(clog) - - LiveUrl := "https://www.openrec.tv/live/" + userId - - streamer.LiveUrl = sql.NullString{String: LiveUrl, Valid: true} - streamer.LatestLogUid = logUid - // streamer.Operator = 0 - - log.Println(streamer.UserId) - estore.Update(streamer, - "user_name", streamer.UserName, - "user_id", streamer.UserId, - "live_url", streamer.LiveUrl, - "latest_log_uid", streamer.LatestLogUid, - "update_time", streamer.UpdateTime, - "tags", streamer.Tags, - ) - - source.Operator = int32(intimate.OperatorExtractorOK) - sstore.UpdateOperator(source) + // streamer.Platform = intimate.Popenrec + streamer.UpdateInterval = 120 + streamer.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} + streamer.Operator = 0 + Extractor(streamer, userId, htmlUser, htmlLive, jsonSupporters) } } + +func Extractor(streamer *intimate.Streamer, userId string, htmlUser, htmlLive string, jsonSupporters []string) { + + // sdata := source.Ext.([]byte) + // datamap := gjson.ParseBytes(sdata).Map() + + // userId := datamap["var_user_id"].String() + + // streamer := &intimate.Streamer{} + // streamer.UserId = &userId + // streamer.Platform = intimate.Popenrec 不需要更新字段 + + // htmlUser := datamap["html_user"] + + userEtor := extractor.ExtractHtmlString(htmlUser) + ui, ok1 := userEtor.GetObjectByTag(UserInfo{}).(*UserInfo) + + // htmlLive := datamap["html_live"] + + liveEtor := extractor.ExtractHtmlString(htmlLive) + ul, ok2 := liveEtor.GetObjectByTag(UserLive{}).(*UserLive) + + // jsonSupporters := datamap["json_supporters"] + clog := &intimate.CollectLog{} + + if ok1 { + clog.Followers = &sql.NullInt64{Int64: ui.Followers, Valid: true} + clog.Views = &sql.NullInt64{Int64: ui.Views, Valid: true} + if ui.Views != 0 { + clog.IsLiveStreaming = true + } + streamer.UserName = &sql.NullString{String: ui.UserName, Valid: true} + + // giverjson := jsonSupporters + var givers []interface{} + var gratuity int64 = 0 + + for _, v := range jsonSupporters { + giverSource := gjson.Parse(v) + for _, item := range giverSource.Get("data.items").Array() { + givers = append(givers, item.Map()) + gratuity += item.Get("total_yells").Int() + } + } + + giversbytes, err := json.Marshal(givers) + if err != nil { + log.Println(err) + clog.ErrorMsg = &sql.NullString{String: err.Error(), Valid: true} + } else { + clog.Giver = giversbytes + } + + clog.Gratuity = &sql.NullInt64{Int64: gratuity, Valid: true} + } else { + log.Println("UserInfo may be not exists") + intimate.TStreamer.UpdateError(streamer, errors.New("UserInfo may be not exists")) + return + } + + //log.Println(ul) + if ok2 { + clog.LiveTitle = &sql.NullString{String: ul.Title, Valid: true} + + startTime, err := time.ParseInLocation("2006-01-02T15:04:05Z07:00", ul.LiveStartTime, time.Local) + if err != nil { + log.Println(err) + } else { + clog.LiveStartTime = &sql.NullTime{Time: startTime.Local(), Valid: true} + duration, err := intimate.ParseDuration(ul.LiveEndTime) + if err != nil { + log.Println(err) + } else { + endTime := startTime.Add(duration) + clog.LiveEndTime = &sql.NullTime{Time: endTime.Local(), Valid: true} + } + } + + if tags, err := json.Marshal(ul.Tags); err == nil { + clog.Tags = tags + } else { + log.Println("json error", ul.Tags, clog.Tags) + } + } + + // streamer.Uid = source.StreamerId.Int64 + // streamer.UpdateTime = &source.UpdateTime + if clog.Tags != nil { + streamer.Tags = clog.Tags + } + clog.Platform = intimate.Popenrec + clog.UserId = userId + clog.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} + clog.StreamerUid = streamer.Uid + + logUid, err := intimate.TClog.InsertRetAutoID(clog) + if err != nil { + log.Println(err) + return + } + + LiveUrl := "https://www.openrec.tv/live/" + userId + + streamer.LiveUrl = &sql.NullString{String: LiveUrl, Valid: true} + streamer.LatestLogUid = logUid + // streamer.Operator = 0 + + // log.Println(*streamer.UserId) + intimate.TStreamer.Update(streamer) + + // source.Operator = int32(intimate.OperatorExtractorOK) + // sstore.UpdateOperator(source) + +} diff --git a/extractor/twitcasting_extractor/twitcasting_extractor.go b/extractor/twitcasting_extractor/twitcasting_extractor.go index c0b6a8e..0fe20a6 100644 --- a/extractor/twitcasting_extractor/twitcasting_extractor.go +++ b/extractor/twitcasting_extractor/twitcasting_extractor.go @@ -5,7 +5,6 @@ import ( "encoding/json" "intimate" "log" - "os" "strconv" "strings" "time" @@ -34,26 +33,35 @@ func main() { ps := intimate.NewPerfectShutdown() ses := requests.NewSession() + streamerQueue := intimate.TStreamer.Queue(intimate.Streamer{}, intimate.ConditionDefault(intimate.Ptwitcasting)) for !ps.IsClose() { - streamer, err := estore.Pop(intimate.Ptwitcasting) + // streamer, err := estore.Pop(intimate.Ptwitcasting) + isteamer, err := streamerQueue.Pop() if err != nil { - log.Println(err, streamer) + log.Println(err, isteamer) + continue } - streamer.LiveUrl = sql.NullString{String: "https://twitcasting.tv/" + streamer.UserId, Valid: true} + streamer := isteamer.(*intimate.Streamer) + streamer.LiveUrl = &sql.NullString{String: "https://twitcasting.tv/" + *streamer.UserId, Valid: true} resp, err := ses.Get(streamer.LiveUrl.String).Execute() if err != nil { - estore.UpdateError(streamer, err) - log.Println(err, streamer.UserId) + intimate.TStreamer.UpdateError(streamer, err) + log.Println(err, *streamer.UserId) continue } var ldata *LiveData - f, _ := os.OpenFile("./twistcasting.html", os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) - f.Write(resp.Content()) + // f, _ := os.OpenFile("./twistcasting.html", os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) + // f.Write(resp.Content()) etor := extractor.ExtractHtml(resp.Content()) - ldata = etor.GetObjectByTag(LiveData{}).(*LiveData) + ildata := etor.GetObjectByTag(LiveData{}) + if ildata == nil { + log.Println(streamer.LiveUrl.String) + continue + } + ldata = ildata.(*LiveData) // ldata.MaxViews = regexp.MustCompile("\\d+").FindString(ldata.MaxViews) coincount := 0 @@ -62,14 +70,14 @@ func main() { giverurl := streamer.LiveUrl.String + "/backers/" + strconv.Itoa(i) resp, err = ses.Get(giverurl).Execute() if err != nil { - estore.UpdateError(streamer, err) + intimate.TStreamer.UpdateError(streamer, err) log.Panic(err) } etor := extractor.ExtractHtml(resp.Content()) xp, err := etor.XPaths("//td[@class='tw-memorial-table-recent-point']") if err != nil { - estore.UpdateError(streamer, err) + intimate.TStreamer.UpdateError(streamer, err) log.Panic(err) } @@ -100,20 +108,20 @@ func main() { } streamer.Platform = intimate.Ptwitcasting - streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} - streamer.UserName = sql.NullString{String: ldata.UserName, Valid: true} + streamer.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} + streamer.UserName = &sql.NullString{String: ldata.UserName, Valid: true} streamer.Operator = 0 streamer.Tags = tags // streamer.UpdateInterval = 60 clog := &intimate.CollectLog{} - clog.UserId = streamer.UserId - clog.Gratuity = sql.NullInt64{Int64: int64(coincount), Valid: true} + clog.UserId = *streamer.UserId + clog.Gratuity = &sql.NullInt64{Int64: int64(coincount), Valid: true} clog.Platform = streamer.Platform clog.UpdateTime = streamer.UpdateTime - clog.LiveTitle = sql.NullString{String: ldata.LiveTitle, Valid: true} + clog.LiveTitle = &sql.NullString{String: ldata.LiveTitle, Valid: true} clog.Tags = tags - clog.Followers = sql.NullInt64{Int64: int64(ldata.Follower), Valid: true} + clog.Followers = &sql.NullInt64{Int64: int64(ldata.Follower), Valid: true} switch { case ldata.Follower <= 100: streamer.UpdateInterval = 720 @@ -125,12 +133,12 @@ func main() { streamer.UpdateInterval = 120 } - clog.Views = sql.NullInt64{Int64: ldata.MaxViews, Valid: true} + clog.Views = &sql.NullInt64{Int64: ldata.MaxViews, Valid: true} if ldata.LiveStart != "" { st, err := time.Parse("Mon, 02 Jan 2006 15:04:05 -0700", ldata.LiveStart) if err == nil { startTime := st - clog.LiveStartTime = sql.NullTime{Time: startTime, Valid: true} + clog.LiveStartTime = &sql.NullTime{Time: startTime, Valid: true} dt, err := strconv.Atoi(ldata.LiveDuration) liveduration := time.Now().Sub(startTime) @@ -149,7 +157,7 @@ func main() { if err == nil { endTime := startTime.Add((time.Duration)(dt) * time.Millisecond) - clog.LiveEndTime = sql.NullTime{Time: endTime, Valid: true} + clog.LiveEndTime = &sql.NullTime{Time: endTime, Valid: true} } else { log.Println(err, streamer.UserId) } @@ -158,8 +166,16 @@ func main() { } } - streamer.LatestLogUid = estore.InsertClog(clog) - estore.UpdateStreamer(streamer) - log.Println(streamer.UserId) + clog.StreamerUid = streamer.Uid + uid, err := intimate.TClog.InsertRetAutoID(clog) + if err != nil { + log.Println(err) + continue + } + + streamer.LatestLogUid = uid + intimate.TStreamer.Update(streamer) + // estore.UpdateStreamer(streamer) + log.Println(*streamer.UserId) } } diff --git a/extractor_field.go b/extractor_field.go index d4266da..3107771 100644 --- a/extractor_field.go +++ b/extractor_field.go @@ -3,26 +3,25 @@ package intimate import ( "database/sql" "reflect" - "time" ) type GetSet struct { } type StreamerList struct { - UrlHash []byte // - Platform Platform // - Url string // + UrlHash string `field:"urlhash" ` // + Platform string `field:"platform" ` // + Url string `field:"url" ` // - Label sql.NullString // + Label *sql.NullString `field:"label" ` // - Serialize interface{} + Serialize interface{} `field:"serialize" ` - UpdateInterval int32 - UpdateTime time.Time // + UpdateInterval int32 `field:"update_interval" ` + UpdateTime *sql.NullTime `field:"update_time" ` // - ErrorMsg sql.NullString - Operator int32 + ErrorMsg *sql.NullString `field:"error_msg" ` // + Operator int32 `field:"operator" ` LastOperator int32 } @@ -51,7 +50,7 @@ type Streamer struct { IsUpdateStreamer bool // 更新上面的内容 IsUpdateUrl bool UpdateInterval int32 `field:"update_interval"` - UpdateUrl interface{} `field:"update_url"` + UpdateUrl interface{} `field:"update_url"` // TODO: nil LatestLogUid int64 `field:"latest_log_uid"` UpdateTime *sql.NullTime `field:"update_time"` // @@ -72,24 +71,24 @@ func (ai *Streamer) Set(field string, value interface{}) { } type CollectLog struct { - LogUid int64 // 日志id - StreamerUid int64 // StreamerId 表id与 + LogUid int64 `field:"log_uid"` // 日志id + StreamerUid int64 `field:"streamer_uid"` // StreamerId 表id与 - Platform Platform // - UserId string // 平台的UserId - IsLiveStreaming bool // - IsError bool // - Followers sql.NullInt64 // - Views sql.NullInt64 // - Giver interface{} // - Gratuity sql.NullInt64 // - LiveTitle sql.NullString // - LiveStartTime sql.NullTime // - LiveEndTime sql.NullTime // - UpdateTime sql.NullTime // - Tags interface{} - Ext interface{} // - ErrorMsg sql.NullString // + Platform Platform `field:"platform"` // + UserId string `field:"user_id"` // 平台的UserId + IsLiveStreaming bool `field:"is_live_streaming"` // + IsError bool `field:"is_error"` // + Followers *sql.NullInt64 `field:"followers"` // + Views *sql.NullInt64 `field:"views"` // + Giver interface{} `field:"giver"` // + Gratuity *sql.NullInt64 `field:"gratuity"` // + LiveTitle *sql.NullString `field:"live_title"` // + LiveStartTime *sql.NullTime `field:"live_start_time"` // + LiveEndTime *sql.NullTime `field:"live_end_time"` // + UpdateTime *sql.NullTime `field:"update_time"` // + Tags interface{} `field:"tags"` + Ext interface{} `field:"ext"` // + ErrorMsg *sql.NullString `field:"error_msg"` // } // Get Simple Value diff --git a/tasks/nimo/nimo_task1/nimo_task1.go b/tasks/nimo/nimo_task1/nimo_task1.go index 96281a3..a5def5c 100644 --- a/tasks/nimo/nimo_task1/nimo_task1.go +++ b/tasks/nimo/nimo_task1/nimo_task1.go @@ -70,13 +70,13 @@ func Execute() { if userid := room.Get("id").String(); userid != "" { - streamer.UserId = userid - streamer.LiveUrl = sql.NullString{String: "https://www.nimo.tv/live/" + userid, Valid: true} + streamer.UserId = &userid + streamer.LiveUrl = &sql.NullString{String: "https://www.nimo.tv/live/" + userid, Valid: true} channel := room.Get("roomTypeName").String() - streamer.Channel = sql.NullString{String: channel, Valid: channel != ""} + streamer.Channel = &sql.NullString{String: channel, Valid: channel != ""} username := room.Get("anchorName").String() - streamer.UserName = sql.NullString{String: username, Valid: username != ""} + streamer.UserName = &sql.NullString{String: username, Valid: username != ""} if rtags := room.Get("anchorLabels"); rtags.IsArray() { diff --git a/tasks/openrec/openrec_task1/task_openrec.go b/tasks/openrec/openrec_task1/task_openrec.go index 40ee747..c46800d 100644 --- a/tasks/openrec/openrec_task1/task_openrec.go +++ b/tasks/openrec/openrec_task1/task_openrec.go @@ -11,11 +11,11 @@ import ( "github.com/tidwall/gjson" ) -// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql -var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STOpenrec)) +// // sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql +// var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STOpenrec)) -// estore 解析存储连接实例 -var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() +// // estore 解析存储连接实例 +// var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() // Execute 执行方法 func Execute() { @@ -71,7 +71,7 @@ func Execute() { userid := User.Get("channel.id").String() streamer := &intimate.Streamer{} - streamer.UserId = userid + streamer.UserId = &userid streamer.Platform = intimate.Popenrec updateUrl := make(map[string]interface{}) @@ -83,15 +83,16 @@ func Execute() { updateUrlBytes, err := json.Marshal(updateUrl) if err != nil { - estore.UpdateError(streamer, err) + intimate.TStreamer.UpdateError(streamer, err) continue } streamer.UpdateUrl = updateUrlBytes - estore.InsertStreamer(streamer) + intimate.TStreamer.Insert(streamer) } } + log.Println("streamer count:", len(result.Array()), tp.ParsedURL.String()) // 修改url query 参数的page递增. 遍历所有页面 tp.QueryParam("page").IntAdd(1) time.Sleep(time.Second * 1) diff --git a/tasks/openrec/openrec_task2/.gitignore b/tasks/openrec/openrec_task2/.gitignore deleted file mode 100644 index 374c872..0000000 --- a/tasks/openrec/openrec_task2/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -openrec_task2 -log diff --git a/tasks/openrec/openrec_task2/main.go b/tasks/openrec/openrec_task2/main.go deleted file mode 100644 index 736ef31..0000000 --- a/tasks/openrec/openrec_task2/main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - Execute() -} diff --git a/tasks/openrec/openrec_task2/task_openrec.go b/tasks/openrec/openrec_task2/task_openrec.go deleted file mode 100644 index abfad26..0000000 --- a/tasks/openrec/openrec_task2/task_openrec.go +++ /dev/null @@ -1,154 +0,0 @@ -package main - -import ( - "database/sql" - "encoding/json" - "intimate" - "log" - "time" - - "github.com/474420502/gcurl" - "github.com/474420502/requests" - "github.com/tidwall/gjson" -) - -// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql -var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STOpenrec)) - -// estore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_extractor.sql -var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() - -func init() { - -} - -// Execute 执行方法 -func Execute() { - - ps := intimate.NewPerfectShutdown() - ses := requests.NewSession() - - var lasterr error = nil - - for !ps.IsClose() { - - streamer, err := estore.Pop(intimate.Popenrec) //队列里弹出一个streamer行. 进行解析 - - if streamer == nil || err != nil { - if err != lasterr { - log.Println(err, lasterr) - lasterr = err - } - time.Sleep(time.Second * 2) - continue - } - - userId := streamer.UserId - - var updateUrl map[string]string - - err = json.Unmarshal(streamer.UpdateUrl.([]byte), &updateUrl) // 反序列化update_url, 里面存了需要采集的url - if err != nil { - log.Println(err) - continue - } - // Check Userid - - userUrl := updateUrl["user"] - log.Println(userUrl) - tp := ses.Get(userUrl) // 获取user url页面数据 - resp, err := tp.Execute() - streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} - - if err != nil { - log.Println(err) - estore.UpdateError(streamer, err) - continue - } - - cookies := ses.GetCookies(tp.GetParsedURL()) - - scurl := updateUrl["supporters"] //获取打赏者的数据 - curl := gcurl.Parse(scurl) - supportersSession := curl.CreateSession() - - temporary := curl.CreateTemporary(supportersSession) - supportersSession.SetCookies(temporary.GetParsedURL(), cookies) - var supporters []string - for { // supporters 数据需要登录信息. 下面为赋值 supporters链接获取的uid token random码 - - supportersQuery := temporary.GetQuery() - - for _, cookie := range cookies { - if cookie.Name == "uuid" { - supportersQuery.Set("Uuid", cookie.Value) - continue - } - - if cookie.Name == "token" { - supportersQuery.Set("Token", cookie.Value) - continue - } - - if cookie.Name == "random" { - supportersQuery.Set("Random", cookie.Value) - continue - } - } - - supportersQuery.Set("identify_id", userId) - temporary.SetQuery(supportersQuery) - - resp, err := temporary.Execute() - if err != nil { - log.Println(err) - } - supporterjson := gjson.ParseBytes(resp.Content()) - supporterdata := supporterjson.Get("data") //解析supporters获取的json数据 - if supporterdata.Type == gjson.Null { - break - } - supporters = append(supporters, string(resp.Content())) - - temporary.QueryParam("page_number").IntAdd(1) - } - - // cookies := cxt.Session().GetCookies(wf.GetParsedURL()) - ext := make(map[string]interface{}) - - ext["json_supporters"] = supporters - ext["html_user"] = string(resp.Content()) - - liveUrl := updateUrl["live"] - tp = ses.Get(liveUrl) - resp, err = tp.Execute() - if err != nil { - log.Println(err) - estore.UpdateError(streamer, err) - continue - } - ext["html_live"] = string(resp.Content()) - ext["var_user_id"] = userId - - extJsonBytes, err := json.Marshal(ext) - if err != nil { - log.Println(err) - estore.UpdateError(streamer, err) - continue - } - - // streamer.Platform = intimate.Popenrec - streamer.UpdateInterval = 120 - streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} - streamer.Operator = 0 - - source := &intimate.Source{} - source.Target = intimate.TOpenrecUser - source.Ext = string(extJsonBytes) - source.StreamerId = sql.NullInt64{Int64: streamer.Uid, Valid: true} - sstore.Insert(source) - - estore.UpdateStreamer(streamer) - } - -} diff --git a/tasks/openrec/openrec_task2/task_openrec_test.go b/tasks/openrec/openrec_task2/task_openrec_test.go deleted file mode 100644 index 80820ef..0000000 --- a/tasks/openrec/openrec_task2/task_openrec_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "testing" -) - -func TestMain(t *testing.T) { - main() -} diff --git a/tasks/twitcasting/twitcasting_task1/twitcasting.go b/tasks/twitcasting/twitcasting_task1/twitcasting.go index dbd5bdf..44a733f 100644 --- a/tasks/twitcasting/twitcasting_task1/twitcasting.go +++ b/tasks/twitcasting/twitcasting_task1/twitcasting.go @@ -75,8 +75,10 @@ func Execute() { sl.Operator = 0 sl.UpdateInterval = 120 sl.UpdateTime = time.Now() + sl.UrlHash = intimate.GetUrlHash(sl.Url) - estore.InsertStreamerList(sl) + intimate.TStreamerList.Insert(sl) + // estore.InsertStreamerList(sl) queue.Put(wurl) queuedict[wurl] = true @@ -107,7 +109,8 @@ func Execute() { sl.Operator = 0 sl.UpdateInterval = 120 sl.UpdateTime = time.Now() - estore.InsertStreamerList(sl) + sl.UrlHash = intimate.GetUrlHash(sl.Url) + intimate.TStreamerList.Insert(sl) queue.Put(wurl) queuedict[wurl] = true diff --git a/tasks/twitch/twitch_task1/task_twitch.go b/tasks/twitch/twitch_task1/task_twitch.go index 03fcaf2..8a6fc0d 100644 --- a/tasks/twitch/twitch_task1/task_twitch.go +++ b/tasks/twitch/twitch_task1/task_twitch.go @@ -1,7 +1,6 @@ package main import ( - "database/sql" "intimate" "log" "time" @@ -9,100 +8,120 @@ import ( "github.com/tebeka/selenium" ) -// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql -var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) +// // sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql +// var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) -// estore 解析存储连接实例 -var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() +// // estore 解析存储连接实例 +// var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() // 获取类型的所有频道链接 // Execute 执行任务 func Execute() { - var err error - wd := intimate.GetChromeDriver(3030) + ps := intimate.NewPerfectShutdown() - weburl := "https://www.twitch.tv/directory?sort=VIEWER_COUNT" - err = wd.Get(weburl) - if err != nil { - panic(err) - } + for !ps.IsClose() { + var err error + wd := intimate.GetChromeDriver(3030) - cardCondition := func(wd selenium.WebDriver) (bool, error) { - elements, err := wd.FindElements(selenium.ByXPATH, "//span/a[contains(@data-a-target,'card-') and @href]") + weburl := "https://www.twitch.tv/directory?sort=VIEWER_COUNT" + err = wd.Get(weburl) if err != nil { - return false, err - } - return len(elements) > 0, nil - } - wd.WaitWithTimeout(cardCondition, time.Second*15) - time.Sleep(time.Second) - - e, err := wd.FindElement(selenium.ByXPATH, "//button[@data-a-target='browse-sort-menu']") - if err != nil { - panic(err) - } - e.Click() - - var hrefs map[string]bool = make(map[string]bool) - var delayerror = 5 - for i := 0; i <= 200; i++ { - cards, err := wd.FindElements(selenium.ByXPATH, "//span/a[contains(@data-a-target,'card-') and @href]") - if err != nil { - log.Println(err) - break + panic(err) } - if len(hrefs) == 0 { - delayerror-- - if delayerror <= 0 { + cardCondition := func(wd selenium.WebDriver) (bool, error) { + elements, err := wd.FindElements(selenium.ByXPATH, "//span/a[contains(@data-a-target,'card-') and @href]") + if err != nil { + return false, err + } + return len(elements) > 0, nil + } + wd.WaitWithTimeout(cardCondition, time.Second*15) + time.Sleep(time.Second) + + e, err := wd.FindElement(selenium.ByXPATH, "//button[@data-a-target='browse-sort-menu']") + if err != nil { + panic(err) + } + e.Click() + + var lasthreflen = 0 + var hrefs map[string]bool = make(map[string]bool) + var delayerror = 5 + for i := 0; i <= 200; i++ { + cards, err := wd.FindElements(selenium.ByXPATH, "//span/a[contains(@data-a-target,'card-') and @href]") + if err != nil { + log.Println(err) break } - } else { - delayerror = 5 - } - for ii := 0; ii < 10; ii++ { - for _, card := range cards { - href, err := card.GetAttribute("href") - if err != nil { - log.Println(href, err) - continue - } else { - hrefs[href] = true + if len(hrefs) == lasthreflen { + delayerror-- + if delayerror <= 0 { + break } + } else { + delayerror = 7 } - break - } + lasthreflen = len(hrefs) - if ps.IsClose() { - break - } + for ii := 0; ii < 10; ii++ { + for _, card := range cards { + href, err := card.GetAttribute("href") + if err != nil { + log.Println(href, err) + continue + } else { + hrefs[href] = true + } + } + break + } - if len(cards) > 10 { - log.Println(len(cards)) - wd.ExecuteScript(`items = document.evaluate("//div[@data-target='directory-page__card-container']/../self::div[@data-target and @style]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + if ps.IsClose() { + break + } + + if len(cards) > 10 { + log.Println(len(cards)) + wd.ExecuteScript(`items = document.evaluate("//div[@data-target='directory-page__card-container']/../self::div[@data-target and @style]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < items.snapshotLength - 10; i++) { item = items.snapshotItem(i); item.remove() ;};`, nil) + } + time.Sleep(time.Millisecond * 200) + wd.KeyDown(selenium.EndKey) + time.Sleep(time.Millisecond * 200) + wd.KeyUp(selenium.EndKey) + time.Sleep(time.Millisecond * 2500) } - time.Sleep(time.Millisecond * 200) - wd.KeyDown(selenium.EndKey) - time.Sleep(time.Millisecond * 200) - wd.KeyUp(selenium.EndKey) - time.Sleep(time.Millisecond * 2500) + + for href := range hrefs { + + sl := &intimate.StreamerList{} + sl.Url = href + sl.UrlHash = intimate.GetUrlHash(sl.Url) + sl.Platform = string(intimate.Ptwitch) + sl.UpdateTime = intimate.GetUpdateTimeNow() + err := intimate.TStreamerList.Insert(sl) + if err != nil { + log.Println(err) + } + + // TODO: Save href + // source := &intimate.Source{} + // source.Source = sql.NullString{String: href, Valid: true} + // source.Operator = 0 + // source.Target = intimate.TTwitchChannel + // source.Url = weburl + // sstore.Insert(source) + } + + log.Println("hrefs len:", len(hrefs)) + // sstore.Deduplicate(intimate.TTwitchChannel, "source") + + wd.Close() + wd.Quit() + time.Sleep(time.Minute * 30) } - - for href := range hrefs { - - // TODO: Save href - source := &intimate.Source{} - source.Source = sql.NullString{String: href, Valid: true} - source.Operator = 0 - source.Target = intimate.TTwitchChannel - source.Url = weburl - sstore.Insert(source) - } - - log.Println("hrefs len:", len(hrefs)) - sstore.Deduplicate(intimate.TTwitchChannel, "source") } diff --git a/utils.go b/utils.go index 6bf7713..1a699b7 100644 --- a/utils.go +++ b/utils.go @@ -1,6 +1,7 @@ package intimate import ( + "crypto/md5" "database/sql" "fmt" "log" @@ -34,6 +35,10 @@ func GetUpdateTimeNow() *sql.NullTime { return &sql.NullTime{Time: time.Now().Add(-time.Hour * 100000), Valid: true} } +func GetUrlHash(urlstr string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(urlstr))) +} + // ParseNumber 去逗号解析数字 func ParseNumber(num string) (int64, error) { num = strings.Trim(num, " ") From b5d5ec04e71893b642d0e3a80634d5e91fef7bf4 Mon Sep 17 00:00:00 2001 From: eson Date: Tue, 8 Sep 2020 18:54:37 +0800 Subject: [PATCH 16/18] TODO: --- tasks/twitch/twitch_task2/task_twitch.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tasks/twitch/twitch_task2/task_twitch.go b/tasks/twitch/twitch_task2/task_twitch.go index 86fcc8f..6f3d399 100644 --- a/tasks/twitch/twitch_task2/task_twitch.go +++ b/tasks/twitch/twitch_task2/task_twitch.go @@ -11,11 +11,11 @@ import ( "github.com/tebeka/selenium" ) -// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql -var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) +// // sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql +// var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) -// estore 解析存储连接实例 -var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() +// // estore 解析存储连接实例 +// var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() // 获取类型的所有频道链接 @@ -132,7 +132,8 @@ func Execute() { matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(href) if len(matches) == 2 { - streamer.UserId = matches[1] + mc := matches[1] + streamer.UserId = &mc } else { log.Println(href) continue @@ -149,7 +150,7 @@ func Execute() { updateUrl := make(map[string]string) updateUrl["live"] = href - streamer.LiveUrl = sql.NullString{String: href, Valid: true} + streamer.LiveUrl = &sql.NullString{String: href, Valid: true} data, err := json.Marshal(updateUrl) if err != nil { log.Println(err) From 30a6c3598053b1b2a51ea094e60a817d3691ceec Mon Sep 17 00:00:00 2001 From: eson Date: Wed, 9 Sep 2020 16:49:44 +0800 Subject: [PATCH 17/18] finish: twitch restructure --- autostore.go | 85 ++++- autostore_test.go | 22 +- .../twitch_extractor/tiwtch_extractor.go | 331 +++++++++++++----- extractor_field.go | 6 +- 4 files changed, 338 insertions(+), 106 deletions(-) diff --git a/autostore.go b/autostore.go index e3c6976..28dcca1 100644 --- a/autostore.go +++ b/autostore.go @@ -34,9 +34,10 @@ type Table struct { name string setting interface{} - updatesql string - selectsql string - insertsql string + updatesql string + selectsql string + insertsql string + duplicatesql string } func NewStore(uri string) *Store { @@ -54,6 +55,7 @@ func (store *Store) Table(name string) *Table { table.name = name table.insertsql = `INSERT INTO ` + table.name + `(%s) values(%s)` + table.duplicatesql = `INSERT INTO ` + table.name + `(%s) values(%s) ON DUPLICATE KEY UPDATE %s` table.updatesql = `UPDATE ` + table.name + ` SET %s WHERE %s = ?` table.selectsql = `SELECT %s FROM ` + table.name + ` WHERE %s ` return table @@ -226,6 +228,83 @@ func (t *Table) Insert(obj interface{}) error { return err } +// DUpdate ON DUPLICATE KEY UPDATE struct. Field对应的tag field字段 +type DUpdate struct { + Field string // selected 字段 + Value interface{} +} + +// InsertOrUpdate nil 不插入. 不支持嵌套. 必须是Ptr类型 +func (t *Table) InsertOrUpdate(obj interface{}, updates ...DUpdate) error { + ov := reflect.ValueOf(obj).Elem() + ot := reflect.TypeOf(obj) + + fieldsql := "" + argssql := "" + + var SourceUpdate []*DUpdate + var OtherUpdate []*DUpdate + for _, u := range updates { + if u.Value == nil { + SourceUpdate = append(SourceUpdate, &u) + } else { + OtherUpdate = append(OtherUpdate, &u) + } + } + + var args []interface{} + for i := 0; i < ov.NumField(); i++ { + field := ov.Field(i) + ftype := ot.Elem().Field(i) + + if fname, ok := ftype.Tag.Lookup("field"); ok { + // if flag, ok := ftype.Tag.Lookup("uid"); ok { + // if flag == "auto" { + // continue + // } + // } + + k := ftype.Type.Kind() + if k == reflect.Ptr || k == reflect.Interface { + if !field.IsNil() { + felem := field.Elem() + args = append(args, felem.Interface()) + fieldsql += fname + "," + argssql += "?," + } + } else { + args = append(args, field.Interface()) + fieldsql += fname + "," + argssql += "?," + } + + for _, u := range SourceUpdate { + if u.Field == fname { + u.Value = args[len(args)-1] + break + } + } + + } + + } + + var duplicateSet string = "" + for _, u := range SourceUpdate { + duplicateSet += u.Field + " = ?," + args = append(args, u.Value) + } + + for _, u := range OtherUpdate { + duplicateSet += u.Field + " = ?," + args = append(args, u.Value) + } + + ssql := fmt.Sprintf(t.duplicatesql, fieldsql[:len(fieldsql)-1], argssql[:len(argssql)-1], duplicateSet[:len(duplicateSet)-1]) + _, err := t.store.db.Exec(ssql, args...) + return err +} + // InsertRetAutoID nil 不插入. 不支持嵌套. 并返回auto uid func (t *Table) InsertRetAutoID(obj interface{}) (int64, error) { ov := reflect.ValueOf(obj).Elem() diff --git a/autostore_test.go b/autostore_test.go index e5a452b..e242fc0 100644 --- a/autostore_test.go +++ b/autostore_test.go @@ -5,26 +5,24 @@ import ( "encoding/json" "testing" "time" - - "github.com/davecgh/go-spew/spew" ) -func estAutoStore(t *testing.T) { +func TestAutoStore(t *testing.T) { uri := "root:@tcp(127.0.0.1:4000)/test?parseTime=true&loc=Local&charset=utf8mb4&collation=utf8mb4_unicode_ci" store := NewStore(uri) - queue := store.Table("streamer").Queue(TSreamer{}, CondWhere{Condition: "operator = 0"}) - re, _ := queue.Pop() + // queue := store.Table("streamer").Queue(TSreamer{}, CondWhere{Condition: "operator = 0"}) + // re, _ := queue.Pop() - pstreamer := re.(*TSreamer) - m := make(map[string]interface{}) - json.Unmarshal(pstreamer.Iface.([]byte), &m) - spew.Println(re.(*TSreamer), m) + // pstreamer := re.(*TSreamer) + // m := make(map[string]interface{}) + // json.Unmarshal(pstreamer.Iface.([]byte), &m) + // spew.Println(re.(*TSreamer), m) streamer := &TSreamer{} - streamer.Uid = 2 - streamer.UserID = &sql.NullString{String: "hehe", Valid: true} + streamer.Uid = 1 + streamer.UserID = &sql.NullString{String: "xixi", Valid: true} streamer.Name = "streamer" streamer.Operator = 0 streamer.Bit = 0b11 @@ -41,7 +39,7 @@ func estAutoStore(t *testing.T) { now := time.Now() streamer.UpdateTime = &now - err = store.Table("streamer").Insert(streamer) + err = store.Table("streamer").InsertOrUpdate(streamer, DUpdate{Field: "userid"}) if err != nil { t.Error(err) } diff --git a/extractor/twitch_extractor/tiwtch_extractor.go b/extractor/twitch_extractor/tiwtch_extractor.go index 2ae0c23..ce65608 100644 --- a/extractor/twitch_extractor/tiwtch_extractor.go +++ b/extractor/twitch_extractor/tiwtch_extractor.go @@ -3,6 +3,7 @@ package main import ( "database/sql" "encoding/json" + "fmt" "intimate" "log" "regexp" @@ -12,134 +13,288 @@ import ( "github.com/tebeka/selenium" ) -// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql -var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) +// // sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql +// var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) -// estore 解析存储连接实例 -var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() +// // estore 解析存储连接实例 +// var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() func main() { - wd := intimate.GetChromeDriver(3030) + wd := intimate.GetChromeDriver(3040) ps := intimate.NewPerfectShutdown() + queue := intimate.TStreamerList.Queue(intimate.StreamerList{}, intimate.ConditionDefault(intimate.Ptwitch)) var count = 0 var countlimt = 200 - var lasterr error = nil + // var lasterr error = nil // var err error - for !ps.IsClose() { - streamer, err := estore.Pop(intimate.Ptwitch) - if streamer == nil || err != nil { - if err != lasterr { - log.Println(err, lasterr) - lasterr = err - } - time.Sleep(time.Second * 2) - continue + + // sourceChannel, err := sstore.Pop(intimate.TTwitchChannel) + isl, err := queue.Pop() + if err != nil { + panic(err) } + streamerlist := isl.(*intimate.StreamerList) - var updateUrl map[string]string - json.Unmarshal(streamer.UpdateUrl.([]byte), &updateUrl) - liveUrl := updateUrl["live"] - liveUrl = strings.Replace(liveUrl, "/watchparty", "", -1) - log.Println(liveUrl) - - // err = wd.Get("https://www.twitch.tv/zoe_0601" + "/about") - err = wd.Get(liveUrl + "/about") + weburl := streamerlist.Url + "?sort=VIEWER_COUNT" + err = wd.Get(weburl) if err != nil { log.Println(err) - estore.UpdateError(streamer, err) - time.Sleep(time.Second * 5) + // sstore.UpdateError(sourceChannel, err) + intimate.TStreamerList.UpdateError(streamerlist, err) + time.Sleep(time.Second * 10) continue } - streamer.LiveUrl = sql.NullString{String: liveUrl, Valid: true} - clog := &intimate.CollectLog{} - clog.UserId = streamer.UserId - clog.Gratuity = sql.NullInt64{Int64: 0, Valid: false} - - time.Sleep(time.Millisecond * 500) - err = extractUserName(wd, streamer) - if err != nil { - _, err = wd.FindElement(selenium.ByXPATH, "//a[@data-a-target='browse-channels-button']") - if err == nil { - log.Println(streamer.UserId, "may be cancell") - streamer.Operator = 5 - streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} - estore.UpdateStreamer(streamer) + wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { + _, err := wd.FindElement(selenium.ByXPATH, "(//div/p[@class=''])[last()]") + if err != nil { + return false, err } - continue - } - err = extractFollowers(wd, clog) - if err != nil { - continue - } + return true, nil + }, time.Second*10) - err = extractViews(wd, clog) // views + tags + gratuity + btn, err := wd.FindElement(selenium.ByXPATH, "//button[@data-a-target='browse-sort-menu']") if err != nil { - // 不直播时提取礼物 gratuity - wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { - channelchat, err := wd.FindElement(selenium.ByXPATH, `//a[@data-a-target="channel-home-tab-Chat"]`) - btn, _ := web.FindElement(selenium.ByXPATH, `//button[@data-test-selector="expand-grabber"]`) - if (err == nil && channelchat != nil) || btn != nil { - if channelchat != nil { - channelchat.Click() - } - time.Sleep(time.Second) - extractGratuity(wd, clog) - return true, nil + log.Println(err) + continue + } + btn.Click() + + var elements []selenium.WebElement + var liveurls = 0 + var delayerror = 2 + for i := 0; i < 200 && !ps.IsClose(); i++ { + elements, err = wd.FindElements(selenium.ByXPATH, "(//div/p[@class=''])[last()]") + if err != nil { + log.Println(err) + break + } + time.Sleep(time.Millisecond * 200) + wd.KeyDown(selenium.EndKey) + time.Sleep(time.Millisecond * 200) + wd.KeyUp(selenium.EndKey) + time.Sleep(time.Millisecond * 2000) + if len(elements) == liveurls { + delayerror-- + if delayerror <= 0 { + break } - return false, nil - - }, time.Second*4) + } else { + delayerror = 2 + } + liveurls = len(elements) + } + articles, err := wd.FindElements(selenium.ByXPATH, "//article") + if err != nil { + log.Println(err) + continue } - streamer.Platform = intimate.Ptwitch - clog.Platform = streamer.Platform - clog.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} - lastClogId := estore.InsertClog(clog) + var streamers []*intimate.Streamer + for _, article := range articles { - streamer.Operator = 10 - streamer.LatestLogUid = lastClogId - if clog.Tags != nil { - streamer.Tags = clog.Tags + e, err := article.FindElement(selenium.ByXPATH, ".//a[@data-a-target='preview-card-title-link' and @href]") + if err != nil { + log.Println(err) + continue + } + + href, err := e.GetAttribute("href") + if err != nil { + log.Println(err) + continue + } + + btns, err := article.FindElements(selenium.ByXPATH, ".//div[@class='tw-full-width tw-inline-block']//button") + if err != nil { + log.Println(err) + continue + } + + var tags []string + for _, btn := range btns { + tag, err := btn.GetAttribute("data-a-target") + if err == nil { + tags = append(tags, tag) + } + } + + streamer := &intimate.Streamer{} + + matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(href) + if len(matches) == 2 { + mc := matches[1] + streamer.UserId = &mc + } else { + log.Println(href) + continue + } + + jtags, err := json.Marshal(tags) + if err != nil { + log.Println(err) + } else { + streamer.Tags = jtags + } + + streamer.Platform = intimate.Ptwitch + streamer.LiveUrl = &sql.NullString{String: href, Valid: true} + streamer.Operator = 0 + + streamers = append(streamers, streamer) + + // if estore.InsertStreamer(streamer) { + // // log.Println("streamer update tags", streamer.Uid, tags) + // if streamer.Tags != nil { + // estore.Update(streamer, "Tags", streamer.Tags) + // } + // } } - switch fl := clog.Followers.Int64; { - case fl > 100000: - streamer.UpdateInterval = 120 - case fl > 10000: - streamer.UpdateInterval = 240 * 2 - case fl > 1000: - streamer.UpdateInterval = 360 * 2 - case fl > 100: - streamer.UpdateInterval = 720 * 2 - case fl > 0: - streamer.UpdateInterval = 1440 * 4 + for _, streamer := range streamers { + Extractor(wd, streamer) + if err = intimate.TStreamer.InsertOrUpdate(streamer, + intimate.DUpdate{Field: "tags"}, + intimate.DUpdate{Field: "update_time"}, + ); err != nil { + log.Println(err) + } + } + + log.Println("streamer find", len(articles)) + if len(articles) == 0 { + intimate.TStreamerList.UpdateError(streamerlist, fmt.Errorf("")) } - streamer.UpdateTime = clog.UpdateTime - estore.UpdateStreamer(streamer) count++ if count >= countlimt { count = 0 - // wd.Quit() - wd = intimate.GetChromeDriver(3030) + wd = intimate.GetChromeDriver(3031) } + } wd.Close() wd.Quit() } +func Extractor(wd selenium.WebDriver, streamer *intimate.Streamer) { + // streamer, err := estore.Pop(intimate.Ptwitch) + // if streamer == nil || err != nil { + // if err != lasterr { + // log.Println(err, lasterr) + // lasterr = err + // } + // time.Sleep(time.Second * 2) + // continue + // } + + // var updateUrl map[string]string + // json.Unmarshal(streamer.UpdateUrl.([]byte), &updateUrl) + liveUrl := streamer.LiveUrl.String + + liveUrl = strings.Replace(liveUrl, "/watchparty", "", -1) + log.Println(liveUrl) + + // err = wd.Get("https://www.twitch.tv/zoe_0601" + "/about") + err := wd.Get(liveUrl + "/about") + if err != nil { + log.Println(err) + intimate.TStreamer.UpdateError(streamer, err) + time.Sleep(time.Second * 5) + return + } + + streamer.LiveUrl = &sql.NullString{String: liveUrl, Valid: true} + clog := &intimate.CollectLog{} + clog.UserId = *streamer.UserId + clog.Gratuity = &sql.NullInt64{Int64: 0, Valid: false} + + time.Sleep(time.Millisecond * 500) + err = extractUserName(wd, streamer) + if err != nil { + _, err = wd.FindElement(selenium.ByXPATH, "//a[@data-a-target='browse-channels-button']") + if err == nil { + log.Println(streamer.UserId, "may be cancell") + streamer.Operator = 5 + streamer.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} + intimate.TStreamer.UpdateError(streamer, fmt.Errorf("")) + } + return + } + err = extractFollowers(wd, clog) + if err != nil { + return + } + + err = extractViews(wd, clog) // views + tags + gratuity + if err != nil { + // 不直播时提取礼物 gratuity + wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + channelchat, err := wd.FindElement(selenium.ByXPATH, `//a[@data-a-target="channel-home-tab-Chat"]`) + btn, _ := web.FindElement(selenium.ByXPATH, `//button[@data-test-selector="expand-grabber"]`) + if (err == nil && channelchat != nil) || btn != nil { + if channelchat != nil { + channelchat.Click() + } + time.Sleep(time.Second) + extractGratuity(wd, clog) + return true, nil + } + return false, nil + + }, time.Second*4) + } + + streamer.Platform = intimate.Ptwitch + clog.Platform = streamer.Platform + clog.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} + // clog.StreamerUid = streamer.Uid + lastClogId, err := intimate.TClog.InsertRetAutoID(clog) + if err != nil { + log.Println(err) + return + } + + streamer.Operator = 10 + streamer.LatestLogUid = lastClogId + if clog.Tags != nil { + streamer.Tags = clog.Tags + } + + switch fl := clog.Followers.Int64; { + case fl > 100000: + streamer.UpdateInterval = 120 + case fl > 10000: + streamer.UpdateInterval = 240 * 2 + case fl > 1000: + streamer.UpdateInterval = 360 * 2 + case fl > 100: + streamer.UpdateInterval = 720 * 2 + case fl > 0: + streamer.UpdateInterval = 1440 * 4 + } + + streamer.UpdateTime = clog.UpdateTime + // intimate.TStreamer.InsertOrUpdate(streamer) + // count++ + // if count >= countlimt { + // count = 0 + // // wd.Quit() + // wd = intimate.GetChromeDriver(3030) + // } +} + func extractUserName(wd selenium.WebDriver, streamer *intimate.Streamer) error { return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { label, err := web.FindElement(selenium.ByXPATH, "//a[@class='tw-interactive']//h1") if err == nil { if ltxt, err := label.Text(); err == nil && ltxt != "" { // log.Println("label:", ltxt) - streamer.UserName = sql.NullString{String: ltxt, Valid: true} + streamer.UserName = &sql.NullString{String: ltxt, Valid: true} return true, nil } } @@ -159,7 +314,7 @@ func extractFollowers(wd selenium.WebDriver, clog *intimate.CollectLog) error { } followers = regexp.MustCompile(`[\d,]+`).FindString(followers) fint, _ := intimate.ParseNumber(followers) - clog.Followers = sql.NullInt64{Int64: int64(fint), Valid: true} + clog.Followers = &sql.NullInt64{Int64: int64(fint), Valid: true} // log.Println("followers: ", followers, fint) return true, nil }, 4*time.Second) @@ -172,7 +327,7 @@ func extractViews(wd selenium.WebDriver, clog *intimate.CollectLog) error { if txt, err := views.Text(); err == nil { vint, _ := intimate.ParseNumber(txt) - clog.Views = sql.NullInt64{Int64: vint, Valid: true} + clog.Views = &sql.NullInt64{Int64: vint, Valid: true} // log.Println("views:", txt) views.Click() @@ -192,7 +347,7 @@ func extractTitle(wd selenium.WebDriver, clog *intimate.CollectLog) error { title, err := web.FindElement(selenium.ByXPATH, `//h2[@data-a-target='stream-title']`) if err == nil { if txt, err := title.Text(); err == nil { - clog.LiveTitle = sql.NullString{String: txt, Valid: true} + clog.LiveTitle = &sql.NullString{String: txt, Valid: true} return true, nil } } @@ -244,7 +399,7 @@ func extractGratuity(wd selenium.WebDriver, clog *intimate.CollectLog) error { log.Println(err) } } - clog.Gratuity = sql.NullInt64{Int64: gratuity, Valid: true} + clog.Gratuity = &sql.NullInt64{Int64: gratuity, Valid: true} } return true, nil } diff --git a/extractor_field.go b/extractor_field.go index 3107771..4e1b691 100644 --- a/extractor_field.go +++ b/extractor_field.go @@ -9,9 +9,9 @@ type GetSet struct { } type StreamerList struct { - UrlHash string `field:"urlhash" ` // - Platform string `field:"platform" ` // - Url string `field:"url" ` // + UrlHash string `field:"urlhash" uid:"true"` // + Platform string `field:"platform" ` // + Url string `field:"url" ` // Label *sql.NullString `field:"label" ` // From a9bb448351f62e2cc21cfed7121216d520d5a278 Mon Sep 17 00:00:00 2001 From: eson Date: Wed, 9 Sep 2020 17:25:36 +0800 Subject: [PATCH 18/18] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extractor/nimo_extractor/nimo_extractor.go | 37 ++-- .../twitch_extractor/tiwtch_extractor.go | 1 - supervisor_conf/openrec_task2.conf | 12 -- supervisor_conf/twitch_extractor.conf | 2 +- ...or_p1.conf => twitch_extractor_p1.conf_eg} | 0 supervisor_conf/twitch_extractor_p2.conf | 13 -- supervisor_conf/twitch_task1.conf | 13 ++ supervisor_conf/twitch_task2.conf | 13 -- tasks/nimo/nimo_task1/nimo_task1.go | 7 +- .../twitcasting_task1/twitcasting.go | 8 +- tasks/twitch/twitch_task2/.gitignore | 2 - tasks/twitch/twitch_task2/main.go | 6 - tasks/twitch/twitch_task2/task_twitch.go | 175 ------------------ tasks/twitch/twitch_task2/task_twitch_test.go | 7 - 14 files changed, 47 insertions(+), 249 deletions(-) delete mode 100644 supervisor_conf/openrec_task2.conf rename supervisor_conf/{twitch_extractor_p1.conf => twitch_extractor_p1.conf_eg} (100%) delete mode 100644 supervisor_conf/twitch_extractor_p2.conf create mode 100644 supervisor_conf/twitch_task1.conf delete mode 100644 supervisor_conf/twitch_task2.conf delete mode 100644 tasks/twitch/twitch_task2/.gitignore delete mode 100644 tasks/twitch/twitch_task2/main.go delete mode 100644 tasks/twitch/twitch_task2/task_twitch.go delete mode 100644 tasks/twitch/twitch_task2/task_twitch_test.go diff --git a/extractor/nimo_extractor/nimo_extractor.go b/extractor/nimo_extractor/nimo_extractor.go index f1bb1b5..d823de5 100644 --- a/extractor/nimo_extractor/nimo_extractor.go +++ b/extractor/nimo_extractor/nimo_extractor.go @@ -11,10 +11,10 @@ import ( ) // sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql -var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STNimo)) +// var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STNimo)) -// estore 解析存储连接实例 -var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() +// // estore 解析存储连接实例 +// var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() func main() { Execute() @@ -35,14 +35,18 @@ func Execute() { waitfor := intimate.NewWaitFor(wd) ps := intimate.NewPerfectShutdown() + queue := intimate.TStreamer.Queue(intimate.Streamer{}, intimate.ConditionDefault(intimate.PNimo)) + for !ps.IsClose() { - streamer, err := estore.Pop(intimate.PNimo) + istreamer, err := queue.Pop() if err != nil { log.Println(err) - estore.UpdateError(streamer, err) + intimate.TStreamer.UpdateError(istreamer, err) continue } + streamer := istreamer.(*intimate.Streamer) + wd.Get(streamer.LiveUrl.String) // wd.Get("https://www.nimo.tv/live/1253835677") @@ -71,22 +75,25 @@ func Execute() { clog := &intimate.CollectLog{} clog.Platform = intimate.PNimo - clog.Followers = sql.NullInt64{Int64: li.Followers, Valid: true} - clog.Views = sql.NullInt64{Int64: li.Views, Valid: true} - clog.UpdateTime = utime + clog.Followers = &sql.NullInt64{Int64: li.Followers, Valid: true} + clog.Views = &sql.NullInt64{Int64: li.Views, Valid: true} + clog.UpdateTime = &utime clog.StreamerUid = streamer.Uid var sum int64 = 0 for _, v := range li.Gratuity { sum += v } - clog.Gratuity = sql.NullInt64{Int64: sum, Valid: true} + clog.Gratuity = &sql.NullInt64{Int64: sum, Valid: true} - cuid := estore.InsertClog(clog) + cuid, err := intimate.TClog.InsertRetAutoID(clog) + if err != nil { + panic(err) + } - streamer.Channel = sql.NullString{String: li.Channel, Valid: true} + streamer.Channel = &sql.NullString{String: li.Channel, Valid: true} streamer.LatestLogUid = cuid - streamer.UpdateTime = utime + streamer.UpdateTime = &utime streamer.Operator = 0 switch { @@ -102,7 +109,11 @@ func Execute() { streamer.UpdateInterval = 60 } - estore.Update(streamer, "update_interval", streamer.UpdateInterval, "operator", streamer.Operator, "channel", streamer.Channel, "latest_log_uid", streamer.LatestLogUid, "update_time", streamer.UpdateTime) + // estore.Update(streamer, "update_interval", streamer.UpdateInterval, "operator", streamer.Operator, "channel", streamer.Channel, "latest_log_uid", streamer.LatestLogUid, "update_time", streamer.UpdateTime) + err = intimate.TStreamer.Update(streamer) + if err != nil { + panic(err) + } count++ if count >= countlimit { diff --git a/extractor/twitch_extractor/tiwtch_extractor.go b/extractor/twitch_extractor/tiwtch_extractor.go index ce65608..8a00fcd 100644 --- a/extractor/twitch_extractor/tiwtch_extractor.go +++ b/extractor/twitch_extractor/tiwtch_extractor.go @@ -123,7 +123,6 @@ func main() { } streamer := &intimate.Streamer{} - matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(href) if len(matches) == 2 { mc := matches[1] diff --git a/supervisor_conf/openrec_task2.conf b/supervisor_conf/openrec_task2.conf deleted file mode 100644 index 1da544f..0000000 --- a/supervisor_conf/openrec_task2.conf +++ /dev/null @@ -1,12 +0,0 @@ -[supervisord] -nodaemon=true - -[program:openrec_source] -directory = MYPATH/bin/openrec_task2/ -command= MYPATH/bin/openrec_task2/openrec_task2 -process_name=%(program_name)s_%(process_num)02d ;多进程名称 -numprocs=4 ;启动多个进程 -autorestart=true -stderr_logfile=MYPATH/bin/openrec_task2/log -stderr_logfile_maxbytes=0 -stopsignal=QUIT diff --git a/supervisor_conf/twitch_extractor.conf b/supervisor_conf/twitch_extractor.conf index 61b82ca..051978a 100644 --- a/supervisor_conf/twitch_extractor.conf +++ b/supervisor_conf/twitch_extractor.conf @@ -1,5 +1,5 @@ [supervisord] -nodaemon=false +nodaemon=true [program:twitch_extractor] environment=DISPLAY=":99" diff --git a/supervisor_conf/twitch_extractor_p1.conf b/supervisor_conf/twitch_extractor_p1.conf_eg similarity index 100% rename from supervisor_conf/twitch_extractor_p1.conf rename to supervisor_conf/twitch_extractor_p1.conf_eg diff --git a/supervisor_conf/twitch_extractor_p2.conf b/supervisor_conf/twitch_extractor_p2.conf deleted file mode 100644 index 4c47d15..0000000 --- a/supervisor_conf/twitch_extractor_p2.conf +++ /dev/null @@ -1,13 +0,0 @@ -[supervisord] -nodaemon=false - -[program:twitch_extractor_p2] -environment=DISPLAY=":99",pac_proxy=http://localhost:1090/pac1 -directory = MYPATH/bin/twitch_extractor -command= MYPATH/bin/twitch_extractor/twitch_extractor -process_name=%(program_name)s_%(process_num)02d ;多进程名称 -numprocs=2 ;启动多个进程 -autorestart=true -stderr_logfile=MYPATH/bin/twitch_extractor/log -stderr_logfile_maxbytes=0 -stopsignal=QUIT diff --git a/supervisor_conf/twitch_task1.conf b/supervisor_conf/twitch_task1.conf new file mode 100644 index 0000000..17a70f6 --- /dev/null +++ b/supervisor_conf/twitch_task1.conf @@ -0,0 +1,13 @@ +[supervisord] +nodaemon=false + +[program:twitch_task1] +environment=DISPLAY=":99" +directory = MYPATH/bin/twitch_task1 +command= MYPATH/bin/twitch_task1/twitch_task1 +# process_name=%(program_name)s_%(process_num)02d ;多进程名称 +# numprocs=1 ;启动多个进程 +autorestart=true +stderr_logfile=MYPATH/bin/twitch_task1/log +stderr_logfile_maxbytes=0 +stopsignal=QUIT diff --git a/supervisor_conf/twitch_task2.conf b/supervisor_conf/twitch_task2.conf deleted file mode 100644 index 8a12047..0000000 --- a/supervisor_conf/twitch_task2.conf +++ /dev/null @@ -1,13 +0,0 @@ -[supervisord] -nodaemon=false - -[program:twitch_task2] -environment=DISPLAY=":99" -directory = MYPATH/bin/twitch_task2 -command= MYPATH/bin/twitch_task2/twitch_task2 -process_name=%(program_name)s_%(process_num)02d ;多进程名称 -numprocs=6 ;启动多个进程 -autorestart=true -stderr_logfile=MYPATH/bin/twitch_task2/log -stderr_logfile_maxbytes=0 -stopsignal=QUIT diff --git a/tasks/nimo/nimo_task1/nimo_task1.go b/tasks/nimo/nimo_task1/nimo_task1.go index a5def5c..e1382c0 100644 --- a/tasks/nimo/nimo_task1/nimo_task1.go +++ b/tasks/nimo/nimo_task1/nimo_task1.go @@ -12,7 +12,7 @@ import ( ) // estore 解析存储连接实例 -var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() +// var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() // Execute 执行 func Execute() { @@ -95,7 +95,10 @@ func Execute() { } streamer.UpdateInterval = 120 - estore.InsertStreamer(streamer) + err = intimate.TStreamer.Insert(streamer) + if err != nil { + panic(err) + } } else { log.Println("userid is null.", room.String()) diff --git a/tasks/twitcasting/twitcasting_task1/twitcasting.go b/tasks/twitcasting/twitcasting_task1/twitcasting.go index 44a733f..efb9ea1 100644 --- a/tasks/twitcasting/twitcasting_task1/twitcasting.go +++ b/tasks/twitcasting/twitcasting_task1/twitcasting.go @@ -70,11 +70,11 @@ func Execute() { if ok := queuedict[wurl]; !ok { log.Println(wurl) sl := &intimate.StreamerList{} - sl.Platform = intimate.Ptwitcasting + sl.Platform = string(intimate.Ptwitcasting) sl.Url = wurl sl.Operator = 0 sl.UpdateInterval = 120 - sl.UpdateTime = time.Now() + sl.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} sl.UrlHash = intimate.GetUrlHash(sl.Url) intimate.TStreamerList.Insert(sl) @@ -104,11 +104,11 @@ func Execute() { sp.TagUrl[i] = wurl if ok := queuedict[wurl]; !ok { sl := &intimate.StreamerList{} - sl.Platform = intimate.Ptwitcasting + sl.Platform = string(intimate.Ptwitcasting) sl.Url = wurl sl.Operator = 0 sl.UpdateInterval = 120 - sl.UpdateTime = time.Now() + sl.UpdateTime = &sql.NullTime{Time: time.Now(), Valid: true} sl.UrlHash = intimate.GetUrlHash(sl.Url) intimate.TStreamerList.Insert(sl) diff --git a/tasks/twitch/twitch_task2/.gitignore b/tasks/twitch/twitch_task2/.gitignore deleted file mode 100644 index 846a6b4..0000000 --- a/tasks/twitch/twitch_task2/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -twitch_task2 -log \ No newline at end of file diff --git a/tasks/twitch/twitch_task2/main.go b/tasks/twitch/twitch_task2/main.go deleted file mode 100644 index e86b640..0000000 --- a/tasks/twitch/twitch_task2/main.go +++ /dev/null @@ -1,6 +0,0 @@ -package main - -func main() { - - Execute() -} diff --git a/tasks/twitch/twitch_task2/task_twitch.go b/tasks/twitch/twitch_task2/task_twitch.go deleted file mode 100644 index 6f3d399..0000000 --- a/tasks/twitch/twitch_task2/task_twitch.go +++ /dev/null @@ -1,175 +0,0 @@ -package main - -import ( - "database/sql" - "encoding/json" - "intimate" - "log" - "regexp" - "time" - - "github.com/tebeka/selenium" -) - -// // sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql -// var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) - -// // estore 解析存储连接实例 -// var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() - -// 获取类型的所有频道链接 - -// Execute 执行任务 -func Execute() { - // DELETE FROM source_twitch WHERE uid NOT IN (SELECT MAX(s.uid) FROM (SELECT uid, source FROM source_twitch ) s GROUP BY s.source) ; - //article//a[@data-a-target='preview-card-title-link'] - - wd := intimate.GetChromeDriver(3030) - defer wd.Quit() - ps := intimate.NewPerfectShutdown() - counter := intimate.NewCounter() - counter.SetMaxLimit(100) - counter.SetMaxToDo(func(olist ...interface{}) error { - owd := olist[0].(*selenium.WebDriver) - if err := (*owd).Quit(); err != nil { - log.Println(err) - } - *owd = intimate.GetChromeDriver(3030) - return nil - }, &wd) - - for !ps.IsClose() { - - var err error - sourceChannel, err := sstore.Pop(intimate.TTwitchChannel) - if err != nil { - panic(err) - } - - weburl := sourceChannel.Source.String + "?sort=VIEWER_COUNT" - err = wd.Get(weburl) - if err != nil { - log.Println(err) - sstore.UpdateError(sourceChannel, err) - time.Sleep(time.Second * 10) - continue - } - - wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { - _, err := wd.FindElement(selenium.ByXPATH, "(//div/p[@class=''])[last()]") - if err != nil { - return false, err - } - return true, nil - }, time.Second*10) - - btn, err := wd.FindElement(selenium.ByXPATH, "//button[@data-a-target='browse-sort-menu']") - if err != nil { - log.Println(err) - continue - } - btn.Click() - - var elements []selenium.WebElement - var liveurls = 0 - var delayerror = 2 - for i := 0; i < 200 && !ps.IsClose(); i++ { - elements, err = wd.FindElements(selenium.ByXPATH, "(//div/p[@class=''])[last()]") - if err != nil { - log.Println(err) - break - } - time.Sleep(time.Millisecond * 200) - wd.KeyDown(selenium.EndKey) - time.Sleep(time.Millisecond * 200) - wd.KeyUp(selenium.EndKey) - time.Sleep(time.Millisecond * 2000) - if len(elements) == liveurls { - delayerror-- - if delayerror <= 0 { - break - } - } else { - delayerror = 2 - } - liveurls = len(elements) - } - articles, err := wd.FindElements(selenium.ByXPATH, "//article") - if err != nil { - log.Println(err) - continue - } - - for _, article := range articles { - - e, err := article.FindElement(selenium.ByXPATH, ".//a[@data-a-target='preview-card-title-link' and @href]") - if err != nil { - log.Println(err) - continue - } - - href, err := e.GetAttribute("href") - if err != nil { - log.Println(err) - continue - } - - btns, err := article.FindElements(selenium.ByXPATH, ".//div[@class='tw-full-width tw-inline-block']//button") - if err != nil { - log.Println(err) - continue - } - - var tags []string - for _, btn := range btns { - tag, err := btn.GetAttribute("data-a-target") - if err == nil { - tags = append(tags, tag) - } - } - - streamer := &intimate.Streamer{} - - matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(href) - if len(matches) == 2 { - mc := matches[1] - streamer.UserId = &mc - } else { - log.Println(href) - continue - } - - jtags, err := json.Marshal(tags) - if err != nil { - log.Println(err) - } else { - streamer.Tags = jtags - } - - streamer.Platform = intimate.Ptwitch - - updateUrl := make(map[string]string) - updateUrl["live"] = href - streamer.LiveUrl = &sql.NullString{String: href, Valid: true} - data, err := json.Marshal(updateUrl) - if err != nil { - log.Println(err) - continue - } - streamer.UpdateUrl = data - streamer.Operator = 0 - if estore.InsertStreamer(streamer) { - // log.Println("streamer update tags", streamer.Uid, tags) - if streamer.Tags != nil { - estore.Update(streamer, "Tags", streamer.Tags) - } - } - } - log.Println("streamer find", len(articles)) - if len(articles) == 0 { - sourceChannel.Operator = 5 - sstore.UpdateOperator(sourceChannel) - } - counter.AddWithReset(1) - } -} diff --git a/tasks/twitch/twitch_task2/task_twitch_test.go b/tasks/twitch/twitch_task2/task_twitch_test.go deleted file mode 100644 index ef64976..0000000 --- a/tasks/twitch/twitch_task2/task_twitch_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "testing" - -func TestMain(t *testing.T) { - main() -}