Compare commits
6 Commits
feature/ad
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2494a8881 | ||
|
|
9e90c80702 | ||
|
|
d041600663 | ||
|
|
750a83bc53 | ||
|
|
0e19b59813 | ||
|
|
fb3b09fc38 |
@@ -145,7 +145,7 @@ func (queue *Queue) Pop() (result interface{}, err error) {
|
||||
rows, err := tx.Query(selectsql, queue.cond.CondArgs...)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("table: %s queue is empty", queue.table.name)
|
||||
return nil, fmt.Errorf("table: %s queue is empty. %s", queue.table.name, err.Error())
|
||||
}
|
||||
|
||||
var fields = make([]interface{}, len(queue.fieldIndex))
|
||||
|
||||
@@ -1 +1,163 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"intimate"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/474420502/gcurl"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
sessionstr := `
|
||||
-H 'authority: www.mirrativ.com'
|
||||
-H 'accept: application/json'
|
||||
-H 'x-timezone: Asia/Shanghai'
|
||||
-H 'x-csrf-token: F3Ojd6RBtApP6YAZzVn-9jWN1of159VxAqOQL1Zn'
|
||||
-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: application/json'
|
||||
-H 'sec-fetch-site: same-origin'
|
||||
-H 'sec-fetch-mode: cors'
|
||||
-H 'sec-fetch-dest: empty'
|
||||
-H 'referer: https://www.mirrativ.com/live/O5Ia4iX9c5CeZj7DFtg52Q'
|
||||
-H 'accept-language: zh-CN,zh;q=0.9,ja;q=0.8'
|
||||
-H 'cookie: f=A2D75F0E-D218-11EA-A042-452BF6D21CE8; _ga=GA1.2.689947597.1596081392; mr_id=kxb65LddGMZf5C28jkR_tGCZD_ZFOAepD5gfXO7eNjfPMB8EKYvU1Vg_Y29V1lsa; _gid=GA1.2.2116692650.1600139685; lang=ja'`
|
||||
|
||||
ps := intimate.NewPerfectShutdown()
|
||||
gprofile := gcurl.Parse(`curl 'https://www.mirrativ.com/api/user/profile?user_id=103383701'` + sessionstr)
|
||||
tpProfile := gprofile.CreateTemporary(nil)
|
||||
tpProfileUserID := tpProfile.QueryParam("user_id")
|
||||
|
||||
g := gcurl.Parse(`culr 'https://www.mirrativ.com/api/live/live?live_id=O5Ia4iX9c5CeZj7DFtg52Q'` + sessionstr)
|
||||
tpLive := g.CreateTemporary(nil)
|
||||
tpLiveID := tpLive.QueryParam("live_id")
|
||||
|
||||
var lasterr error
|
||||
queue := intimate.TStreamer.Queue(intimate.Streamer{}, intimate.ConditionDefault(intimate.PMirrativ))
|
||||
for !ps.IsClose() {
|
||||
istreamer, err := queue.Pop()
|
||||
if err != nil {
|
||||
if lasterr != err {
|
||||
lasterr = err
|
||||
log.Println(err)
|
||||
}
|
||||
ps.Wait(time.Second * 5)
|
||||
continue
|
||||
}
|
||||
|
||||
now := &sql.NullTime{Time: time.Now(), Valid: true}
|
||||
streamer := istreamer.(*intimate.Streamer)
|
||||
streamer.UpdateTime = now
|
||||
userid := *streamer.UserId
|
||||
log.Println(userid)
|
||||
|
||||
tpProfileUserID.StringSet(userid)
|
||||
resp, err := tpProfile.Execute()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
clog := &intimate.CollectLog{}
|
||||
clog.Platform = intimate.PMirrativ
|
||||
clog.UpdateTime = now
|
||||
clog.UserId = userid
|
||||
clog.StreamerUid = streamer.Uid
|
||||
|
||||
profilejson := gjson.ParseBytes(resp.Content())
|
||||
if result := profilejson.Get("follower_num"); result.Exists() {
|
||||
clog.Followers = &sql.NullInt64{Int64: result.Int(), Valid: true}
|
||||
}
|
||||
|
||||
if result := profilejson.Get("onlive.live_id"); result.Exists() {
|
||||
liveID := result.String()
|
||||
tpLiveID.StringSet(liveID)
|
||||
resp, err = tpLive.Execute()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
livejson := gjson.ParseBytes(resp.Content())
|
||||
if result := livejson.Get("total_viewer_num"); result.Exists() {
|
||||
clog.Views = &sql.NullInt64{Int64: result.Int(), Valid: true}
|
||||
}
|
||||
|
||||
if result := livejson.Get("max_online_viewer_num"); result.Exists() {
|
||||
clog.PCU = &sql.NullInt64{Int64: result.Int(), Valid: true}
|
||||
}
|
||||
|
||||
if result := livejson.Get("title"); result.Exists() {
|
||||
clog.LiveTitle = &sql.NullString{String: result.String(), Valid: true}
|
||||
}
|
||||
|
||||
if result := livejson.Get("started_at"); result.Exists() {
|
||||
clog.LiveStartTime = &sql.NullTime{Time: time.Unix(result.Int(), 0), Valid: true}
|
||||
}
|
||||
|
||||
if result := livejson.Get("heartbeated_at"); result.Exists() {
|
||||
clog.LiveEndTime = &sql.NullTime{Time: time.Unix(result.Int(), 0), Valid: true}
|
||||
}
|
||||
|
||||
if result := livejson.Get("app_id"); result.Exists() {
|
||||
streamer.Channel = &sql.NullString{String: result.String(), Valid: true}
|
||||
}
|
||||
|
||||
if result := livejson.Get("timeline.#.app.short_title"); result.Exists() {
|
||||
for _, tl := range result.Array() {
|
||||
var tags []string = []string{tl.String()}
|
||||
jtags, _ := json.Marshal(tags)
|
||||
streamer.Tags = jtags
|
||||
clog.Tags = jtags
|
||||
break
|
||||
}
|
||||
} else {
|
||||
log.Println(string(resp.Content()))
|
||||
return
|
||||
}
|
||||
|
||||
if result := livejson.Get("gift_ranking_url"); result.Exists() {
|
||||
// streamer.Channel = &sql.NullString{String: result.String(), Valid: true}
|
||||
gifturl := "curl '" + result.String() + "&type=monthly&cursor='" + sessionstr
|
||||
ggift := gcurl.Parse(gifturl)
|
||||
tp := ggift.CreateTemporary(nil)
|
||||
tp.SetURLRawPath("/api/gift/ranking")
|
||||
pcursor := tp.QueryParam("cursor")
|
||||
var gratuity int64 = 0
|
||||
|
||||
for {
|
||||
giftdata, err := tp.Execute()
|
||||
giftjson := gjson.ParseBytes(giftdata.Content())
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
for _, rpoint := range giftjson.Get("ranking.#.point").Array() {
|
||||
gratuity += rpoint.Int()
|
||||
}
|
||||
}
|
||||
ncursor := giftjson.Get("next_cursor").String()
|
||||
if ncursor == "" {
|
||||
break
|
||||
}
|
||||
pcursor.StringSet(ncursor)
|
||||
}
|
||||
// https://www.mirrativ.com/gift/ranking?live_id=O5Ia4iX9c5CeZj7DFtg52Q&obfuscated_user_id=PgIBEgc6jVc
|
||||
clog.Gratuity = &sql.NullInt64{Int64: gratuity, Valid: true}
|
||||
}
|
||||
|
||||
cid, err := intimate.TClog.InsertRetAutoID(clog)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
streamer.LatestLogUid = cid
|
||||
}
|
||||
|
||||
intimate.TStreamer.Update(streamer)
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"intimate"
|
||||
"log"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/474420502/gcurl"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
ps := intimate.NewPerfectShutdown()
|
||||
gprofile := gcurl.Parse(`https://www.mirrativ.com/api/user/profile?user_id=103383701`)
|
||||
tpProfile := gprofile.CreateTemporary(nil)
|
||||
tpProfileUserID := tpProfile.QueryParam("user_id")
|
||||
|
||||
g := gcurl.Parse(`https://www.mirrativ.com/api/live/live?live_id=O5Ia4iX9c5CeZj7DFtg52Q`)
|
||||
tpLive := g.CreateTemporary(nil)
|
||||
tpLiveID := tpLive.QueryParam("live_id")
|
||||
|
||||
queue := intimate.TStreamer.Queue(intimate.Streamer{}, intimate.ConditionDefault(intimate.PMirrativ))
|
||||
for !ps.IsClose() {
|
||||
istreamer, err := queue.Pop()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
time.Sleep(time.Second * 2)
|
||||
continue
|
||||
}
|
||||
|
||||
streamer := istreamer.(*intimate.Streamer)
|
||||
userid := *streamer.UserId
|
||||
|
||||
tpProfileUserID.StringSet(userid)
|
||||
resp, err := tpProfile.Execute()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
profilejson := gcurl.Parse(string(resp.Content()))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDo(t *testing.T) {
|
||||
main()
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
type UserInfo struct {
|
||||
UserName string `exp:"//p[ contains(@class, 'c-global__user__profile__list__name__text')]"`
|
||||
Followers int64 `exp:"//p[@class='c-global__user__count__row__right js-userCountFollowers']" mth:"r:ParseNumber"`
|
||||
Views int64 `exp:"//ul[@class='c-contents']//p[@class='c-thumbnailVideo__footer__liveCount']" mth:"r:ExtractNumber"`
|
||||
PCU int64 `exp:"//ul[@class='c-contents']//p[@class='c-thumbnailVideo__footer__liveCount']" mth:"r:ExtractNumber"`
|
||||
}
|
||||
|
||||
//UserLive 提取信息的结构体
|
||||
@@ -27,6 +27,7 @@ type UserLive struct {
|
||||
LiveStartTime string `exp:"//meta[@itemprop='uploadDate']/@content"`
|
||||
LiveEndTime string `exp:"//meta[@itemprop='duration']/@content"`
|
||||
Tags []string `exp:"//div[contains(@class,'MovieMetaContent__TagContainer')]//a[@role ='button']"`
|
||||
Views int64 `exp:"//meta[@itemprop='interactionCount']/@content"`
|
||||
}
|
||||
|
||||
// Execute 执行
|
||||
@@ -173,10 +174,7 @@ func Extractor(streamer *intimate.Streamer, userId string, htmlUser, htmlLive st
|
||||
|
||||
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
|
||||
}
|
||||
clog.PCU = &sql.NullInt64{Int64: ui.PCU, Valid: true}
|
||||
streamer.UserName = &sql.NullString{String: ui.UserName, Valid: true}
|
||||
|
||||
// giverjson := jsonSupporters
|
||||
@@ -208,6 +206,7 @@ func Extractor(streamer *intimate.Streamer, userId string, htmlUser, htmlLive st
|
||||
|
||||
//log.Println(ul)
|
||||
if ok2 {
|
||||
clog.Views = &sql.NullInt64{Int64: ul.Views, Valid: true}
|
||||
clog.LiveTitle = &sql.NullString{String: ul.Title, Valid: true}
|
||||
|
||||
startTime, err := time.ParseInLocation("2006-01-02T15:04:05Z07:00", ul.LiveStartTime, time.Local)
|
||||
|
||||
@@ -13,12 +13,6 @@ import (
|
||||
"github.com/474420502/requests"
|
||||
)
|
||||
|
||||
// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql
|
||||
var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STOpenrec))
|
||||
|
||||
// estore 解析存储连接实例
|
||||
var estore *intimate.StoreExtractor = intimate.NewStoreExtractor()
|
||||
|
||||
type LiveData struct {
|
||||
UserName string `exp:"//span[@class='tw-live-author__info-username']" method:"Text"`
|
||||
Follower int64 `exp:"(//span[@class='tw-user-nav-list-count'])[2]" method:"r:ExtractNumber"`
|
||||
|
||||
@@ -365,6 +365,7 @@ func extractViews(wd selenium.WebDriver, clog *intimate.CollectLog) error {
|
||||
|
||||
vint, _ := intimate.ParseNumber(txt)
|
||||
clog.Views = &sql.NullInt64{Int64: vint, Valid: true}
|
||||
clog.PCU = clog.Views
|
||||
// log.Println("views:", txt)
|
||||
views.Click()
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ type Streamer struct {
|
||||
Channel *sql.NullString `field:"channel"` //
|
||||
Tags interface{} `field:"tags"`
|
||||
Ext interface{} `field:"ext"` //
|
||||
Comments interface{} `field:"comments"`
|
||||
// Comments interface{} `field:"comments"`
|
||||
|
||||
IsUpdateStreamer bool // 更新上面的内容
|
||||
IsUpdateUrl bool
|
||||
@@ -75,22 +75,22 @@ type CollectLog struct {
|
||||
LogUid int64 `field:"log_uid"` // 日志id
|
||||
StreamerUid int64 `field:"streamer_uid"` // StreamerId 表id与
|
||||
|
||||
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"` //
|
||||
Comments interface{} `field:"comments"` //
|
||||
Platform Platform `field:"platform"` //
|
||||
UserId string `field:"user_id"` // 平台的UserId
|
||||
PCU *sql.NullInt64 `field:"pcu"` //
|
||||
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"` //
|
||||
Comments interface{} `field:"comments"` //
|
||||
}
|
||||
|
||||
// Get Simple Value
|
||||
|
||||
443
store.go
443
store.go
@@ -1,12 +1,7 @@
|
||||
package intimate
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
@@ -47,441 +42,3 @@ type StoreSource struct {
|
||||
errorCount int
|
||||
errorLimit int
|
||||
}
|
||||
|
||||
func (store *StoreSource) PopCount() int {
|
||||
return store.popCount
|
||||
}
|
||||
|
||||
func (store *StoreSource) Close() error {
|
||||
return store.db.Close()
|
||||
}
|
||||
|
||||
// NewSourceStore 创建一个存储实例
|
||||
func NewStoreSource(table string) *StoreSource {
|
||||
db, err := sql.Open("mysql", InitConfig.Database.SourceURI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &StoreSource{table: table, db: db}
|
||||
}
|
||||
|
||||
func (store *StoreSource) errorAlarm(err error) {
|
||||
if err != nil {
|
||||
log.Println("store error: ", err)
|
||||
// 报警. 如果数据插入有问题
|
||||
store.errorCount++
|
||||
if store.errorCount >= store.errorLimit {
|
||||
// 数据库频繁操作初问题 报警, 减少没意义的请求
|
||||
}
|
||||
} else {
|
||||
if store.errorCount > 0 {
|
||||
store.errorCount--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert 插入数据
|
||||
func (store *StoreSource) Insert(isource IGet) {
|
||||
_, err := store.db.Exec("insert into "+store.table+"(url, target_type, source, ext, operator, error_msg, streamer_id) values(?,?,?,?,?,?,?)", isource.Get("Url"), isource.Get("Target"), isource.Get("Source"), isource.Get("Ext"), isource.Get("Operator"), isource.Get("ErrorMsg"), isource.Get("StreamerId"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplicate 去重
|
||||
func (store *StoreSource) Deduplicate(target Target, field string) {
|
||||
sql := `DELETE FROM ` + store.table + ` WHERE uid NOT IN (SELECT MAX(s.uid) FROM (SELECT uid, ` + field + ` FROM ` + store.table + ` force index(target_type_idx) WHERE target_type = "` + string(target) + `" ) s GROUP BY s.` + string(field) + `) ;`
|
||||
_, err := store.db.Exec(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Update 更新数据
|
||||
func (store *StoreSource) Update(isource IGet) {
|
||||
_, err := store.db.Exec("update "+store.table+" set ext = ?, pass_gob = ?, operator = ?, error_msg = ? where uid = ?", isource.Get("Ext"), isource.Get("PassGob"), isource.Get("Operator"), isource.Get("ErrorMsg"), isource.Get("Uid"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateOperator 更新数据操作标志位
|
||||
func (store *StoreSource) UpdateOperator(isource IGet) {
|
||||
_, err := store.db.Exec("update "+store.table+" set operator = ?, error_msg = ? where uid = ?", isource.Get("Operator"), isource.Get("ErrorMsg"), isource.Get("Uid"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateError 更新错误数据
|
||||
func (store *StoreSource) UpdateError(isource IGetSet, err error) {
|
||||
isource.Set("Operator", int32(OperatorError)+isource.Get("Operator").(int32))
|
||||
isource.Set("ErrorMsg", sql.NullString{String: err.Error(), Valid: true})
|
||||
_, dberr := store.db.Exec("update "+store.table+" set operator = ?, error_msg = ? where uid = ?", isource.Get("Operator"), isource.Get("ErrorMsg"), isource.Get("Uid"))
|
||||
if dberr != nil {
|
||||
// email tell owner to deal with
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Restore 恢复Operator数据状态
|
||||
func (store *StoreSource) Restore(isource IGet) {
|
||||
_, dberr := store.db.Exec("update "+store.table+" set operator = ? where uid = ?", isource.Get("LastOperator"), isource.Get("Uid"))
|
||||
if dberr != nil {
|
||||
// email tell owner to deal with
|
||||
panic(dberr)
|
||||
}
|
||||
}
|
||||
|
||||
// Pop 弹出一条未处理的数据
|
||||
func (store *StoreSource) Pop(targetType Target, operators ...int32) (*Source, error) {
|
||||
|
||||
tx, err := store.db.Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var args = []interface{}{string(targetType)}
|
||||
selectSQL := `select uid, url, target_type, source, ext, operator, update_time, streamer_id from ` + store.table + ` where target_type = ?`
|
||||
if len(operators) == 0 {
|
||||
selectSQL += " and operator = ?"
|
||||
args = append(args, 0)
|
||||
} else {
|
||||
for _, operator := range operators {
|
||||
selectSQL += " and operator = ?"
|
||||
args = append(args, operator)
|
||||
}
|
||||
}
|
||||
|
||||
// log.Println(selectSQL + ` limit 1 for update`)
|
||||
row := tx.QueryRow(selectSQL+` limit 1 for update`, args...)
|
||||
|
||||
defer func() {
|
||||
err := tx.Commit()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
err = tx.Rollback()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
store.popCount++
|
||||
}()
|
||||
|
||||
s := &Source{}
|
||||
// uid, url, target_type, source, ext, operator
|
||||
err = row.Scan(&s.Uid, &s.Url, &s.Target, &s.Source, &s.Ext, &s.Operator, &s.UpdateTime, &s.StreamerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Set("LastOperator", s.Operator)
|
||||
_, err = tx.Exec("update "+store.table+" set operator = ? where uid = ?", OperatorWait, s.Uid)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// StreamerTable 主播表名称
|
||||
const StreamerTable string = "streamer"
|
||||
|
||||
// CollectLogTable 采集日志表
|
||||
const CollectLogTable string = "collect_log"
|
||||
|
||||
// StreamerListTable 主播表名称
|
||||
const StreamerListTable string = "streamer_list"
|
||||
|
||||
type StoreExtractor struct {
|
||||
db *sql.DB
|
||||
|
||||
popCount int
|
||||
errorCount int
|
||||
errorLimit int
|
||||
}
|
||||
|
||||
func (store *StoreExtractor) PopCount() int {
|
||||
return store.popCount
|
||||
}
|
||||
|
||||
func (store *StoreExtractor) Close() error {
|
||||
return store.db.Close()
|
||||
}
|
||||
|
||||
func (store *StoreExtractor) errorAlarm(err error) {
|
||||
if err != nil {
|
||||
log.Println("store error: ", err)
|
||||
// 报警. 如果数据插入有问题
|
||||
store.errorCount++
|
||||
if store.errorCount >= store.errorLimit {
|
||||
// 数据库频繁操作初问题 报警, 减少没意义的请求
|
||||
}
|
||||
} else {
|
||||
if store.errorCount > 0 {
|
||||
store.errorCount--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewStoreExtractor 生成一个extractor库的相关链接
|
||||
func NewStoreExtractor() *StoreExtractor {
|
||||
db, err := sql.Open("mysql", InitConfig.Database.ExtractorURI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
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 {
|
||||
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 ` + condition
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
s.Set("LastOperator", s.Operator)
|
||||
_, err = tx.Exec("update "+StreamerTable+" set operator = ? where uid = ?", OperatorWait, s.Uid)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// UpdateStreamerList streamerlist表, 更新数据
|
||||
func (store *StoreExtractor) UpdateStreamerList(streamer IGet, fieldvalues ...interface{}) {
|
||||
updateSQL := "UPDATE " + StreamerListTable + " SET "
|
||||
var values []interface{}
|
||||
for i := 0; i < len(fieldvalues); i += 2 {
|
||||
field := fieldvalues[i]
|
||||
values = append(values, fieldvalues[i+1])
|
||||
updateSQL += field.(string) + " = ? "
|
||||
}
|
||||
updateSQL += "WHERE urlhash = ?"
|
||||
values = append(values, streamer.Get("UrlHash"))
|
||||
_, err := store.db.Exec(updateSQL, values...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// InsertStreamer streamerlist表, 插入数据
|
||||
func (store *StoreExtractor) InsertStreamerList(streamerlist IGet) (isExists bool) {
|
||||
urlstr := streamerlist.Get("Url").(string)
|
||||
|
||||
_, err := store.db.Exec("insert into streamer_list(urlhash, url, platform, label, serialize, update_interval, error_msg, operator) values(?,?,?,?,?,?,?,?)",
|
||||
fmt.Sprintf("%x", md5.Sum([]byte(urlstr))),
|
||||
urlstr,
|
||||
streamerlist.Get("Platform"),
|
||||
streamerlist.Get("Label"),
|
||||
streamerlist.Get("Serialize"),
|
||||
streamerlist.Get("UpdateInterval"),
|
||||
streamerlist.Get("ErrorMsg"),
|
||||
streamerlist.Get("Operator"),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if !strings.HasPrefix(err.Error(), "Error 1062") {
|
||||
log.Println(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// InsertStreamer Streamer表, 插入数据
|
||||
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 = ?"
|
||||
tx, err := store.db.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
rerr := tx.Rollback()
|
||||
if rerr != nil {
|
||||
log.Println(rerr)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UpdateError 更新错误数据
|
||||
func (store *StoreExtractor) UpdateError(isource IGetSet, err error) {
|
||||
isource.Set("Operator", int32(OperatorError)+isource.Get("Operator").(int32))
|
||||
isource.Set("ErrorMsg", sql.NullString{String: err.Error(), Valid: true})
|
||||
_, dberr := store.db.Exec("update "+StreamerTable+" set operator = ?, error_msg = ? where uid = ?", isource.Get("Operator"), isource.Get("ErrorMsg"), isource.Get("Uid"))
|
||||
if dberr != nil {
|
||||
// email tell owner to deal with
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateStreamerLog 只更新Streamer的关联日志和时间戳
|
||||
func (store *StoreExtractor) UpdateStreamerLog(latestUid int64, streamerUid int64) {
|
||||
_, err := store.db.Exec("UPDATE "+StreamerTable+" SET latest_log_uid = ?, update_time = CURRENT_TIMESTAMP() WHERE uid = ?", latestUid, streamerUid)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateOperator Streamer表, 插入数据
|
||||
func (store *StoreExtractor) UpdateOperator(isource IGet) {
|
||||
_, err := store.db.Exec("update "+StreamerTable+" set operator = ?, error_msg = ? where uid = ?", isource.Get("Operator"), isource.Get("ErrorMsg"), isource.Get("Uid"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateStreamer Streamer表, 插入数据
|
||||
func (store *StoreExtractor) UpdateStreamer(streamer IGet) {
|
||||
// log.Printf("UPDATE "+StreamerTable+" SET user_name = %v, live_url = %v, channel = %v, latest_log_uid = %v, tags = %v, ext = %v, operator = %v, update_time = %v, update_interval = %v WHERE uid = %v", streamer.Get("UserName"), streamer.Get("LiveUrl"), streamer.Get("Channel"), streamer.Get("LatestLogUid"), streamer.Get("Tags"), streamer.Get("Ext"), streamer.Get("Operator"), streamer.Get("UpdateTime"), streamer.Get("UpdateInterval"), streamer.Get("Uid"))
|
||||
_, err := store.db.Exec("UPDATE "+StreamerTable+" SET user_name = ?, live_url = ?, channel = ?, latest_log_uid = ?, tags = ?, ext = ?, operator = ?, update_time = ?, update_interval = ? WHERE uid = ?",
|
||||
streamer.Get("UserName"), streamer.Get("LiveUrl"), streamer.Get("Channel"), streamer.Get("LatestLogUid"), streamer.Get("Tags"), streamer.Get("Ext"), streamer.Get("Operator"), streamer.Get("UpdateTime"), streamer.Get("UpdateInterval"), streamer.Get("Uid"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Update Streamer表, 更新指定的字段
|
||||
func (store *StoreExtractor) Update(streamer IGet, fieldvalues ...interface{}) {
|
||||
updateSQL := "UPDATE " + StreamerTable + " SET "
|
||||
var values []interface{}
|
||||
for i := 0; i < len(fieldvalues); i += 2 {
|
||||
field := fieldvalues[i]
|
||||
values = append(values, fieldvalues[i+1])
|
||||
updateSQL += field.(string) + " = ?,"
|
||||
}
|
||||
updateSQL = updateSQL[0 : len(updateSQL)-1]
|
||||
updateSQL += "WHERE uid = ?"
|
||||
values = append(values, streamer.Get("Uid"))
|
||||
_, err := store.db.Exec(updateSQL, values...)
|
||||
if err != nil {
|
||||
log.Println(updateSQL)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// InsertClog CollectLog表插入数据
|
||||
func (store *StoreExtractor) InsertClog(clog IGet) int64 {
|
||||
tx, err := store.db.Begin()
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
tx.Rollback()
|
||||
log.Panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
result, err := tx.Exec("insert into "+CollectLogTable+"(streamer_uid, platform, user_id, is_live_streaming, is_error, followers, views, giver, gratuity, live_title, live_start_time, live_end_time, update_time, tags, ext, error_msg) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
clog.Get("StreamerUid"), clog.Get("Platform"), clog.Get("UserId"), clog.Get("IsLiveStreaming"), clog.Get("IsError"), clog.Get("Followers"), clog.Get("Views"), clog.Get("Giver"), clog.Get("Gratuity"), clog.Get("LiveTitle"), clog.Get("LiveStartTime"), clog.Get("LiveEndTime"), clog.Get("UpdateTime"), clog.Get("Tags"), clog.Get("Ext"), clog.Get("ErrorMsg"),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logUid, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec("update "+StreamerTable+" set latest_log_uid = ? where uid = ?", logUid, clog.Get("StreamerUid"))
|
||||
if err = tx.Commit(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return logUid
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CURPATH=`pwd`
|
||||
BINPATH=$(dirname "$CURPATH")/bin
|
||||
find $BINPATH -type f -name 'log' -exec rm {} +
|
||||
find $BINPATH -type f -name 'log' -exec truncate -s 0 {} +
|
||||
|
||||
|
||||
|
||||
|
||||
10
supervisor_conf/mirrativ_extractor.conf
Normal file
10
supervisor_conf/mirrativ_extractor.conf
Normal file
@@ -0,0 +1,10 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
|
||||
[program:mirrativ_extractor]
|
||||
directory = MYPATH/bin/mirrativ_extractor/
|
||||
command= MYPATH/bin/mirrativ_extractor/mirrativ_extractor
|
||||
autorestart=true
|
||||
stderr_logfile=MYPATH/bin/mirrativ_extractor/log
|
||||
stderr_logfile_maxbytes=0
|
||||
stopsignal=QUIT
|
||||
13
supervisor_conf/mirrativ_task1.conf
Normal file
13
supervisor_conf/mirrativ_task1.conf
Normal file
@@ -0,0 +1,13 @@
|
||||
[supervisord]
|
||||
nodaemon=false
|
||||
|
||||
[program:mirrativ_task1]
|
||||
environment=DISPLAY=":99"
|
||||
directory = MYPATH/bin/mirrativ_task1/
|
||||
command= MYPATH/bin/mirrativ_task1/mirrativ_task1
|
||||
# process_name=%(program_name)s_%(process_num)02d ;多进程名称
|
||||
# numprocs=1 ;启动多个进程
|
||||
autorestart=true
|
||||
stderr_logfile=MYPATH/bin/mirrativ_task1/log
|
||||
stderr_logfile_maxbytes=0
|
||||
stopsignal=QUIT
|
||||
@@ -31,7 +31,8 @@ func main() {
|
||||
cursor := tp.QueryParam(`cursor`)
|
||||
cursor.StringSet("")
|
||||
|
||||
for {
|
||||
ps := intimate.NewPerfectShutdown()
|
||||
for !ps.IsClose() {
|
||||
|
||||
log.Println(tp.ParsedURL.String())
|
||||
resp, err := tp.Execute()
|
||||
@@ -57,14 +58,15 @@ func main() {
|
||||
streamer.Platform = intimate.PMirrativ
|
||||
streamer.Operator = 0
|
||||
streamer.UserId = &guserid.Str
|
||||
streamer.UserName = &sql.NullString{String: liveinfo.Get("name").String(), Valid: true}
|
||||
streamer.UpdateInterval = 60
|
||||
streamer.UserName = &sql.NullString{String: owner.Get("name").String(), Valid: true}
|
||||
streamer.UpdateInterval = 600
|
||||
streamer.UpdateTime = intimate.GetUpdateTimeNow()
|
||||
|
||||
err = intimate.TStreamer.InsertOrUpdate(
|
||||
streamer,
|
||||
intimate.DUpdate{Field: "update_time"},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
panic(err)
|
||||
@@ -72,9 +74,9 @@ func main() {
|
||||
}
|
||||
}
|
||||
if next == "" {
|
||||
time.Sleep(time.Minute * 5)
|
||||
ps.Wait(time.Minute * 10)
|
||||
} else {
|
||||
time.Sleep(time.Second * 2)
|
||||
ps.Wait(time.Second * 2)
|
||||
}
|
||||
cursor.StringSet(next)
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
|
||||
main()
|
||||
}
|
||||
|
||||
@@ -14,12 +14,6 @@ import (
|
||||
"github.com/474420502/requests"
|
||||
)
|
||||
|
||||
// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql
|
||||
var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitcasting))
|
||||
|
||||
// estore 解析存储连接实例
|
||||
var estore *intimate.StoreExtractor = intimate.NewStoreExtractor()
|
||||
|
||||
type SearchProfile struct {
|
||||
UserName string `exp:".//span[@class='username']" method:"Text"`
|
||||
UserId string // `exp:".//span[@class='fullname']" method:"Text"`
|
||||
|
||||
@@ -2361,4 +2361,205 @@
|
||||
"collab_enabled": 1,
|
||||
"image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/thumbnail_image_url/9bfba1b91a486106882577717aab4ccb4113b200d07dfb7127b087e4e52d8869_m.jpeg?1600164645",
|
||||
"orientation_v2": "6"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
"obfuscated_user_id": "PgIBEgc6jVc",
|
||||
"current_user_rank": null,
|
||||
"ranking": [
|
||||
{
|
||||
"point": 10,
|
||||
"user": {
|
||||
"share_url": "https://www.mirrativ.com/user/105481237",
|
||||
"profile_image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/profile_image/2d16160a4158c99daf92f287313a7b4df7797b9f1e07ae0f8983df42fbecec97_m.jpeg?1600205857",
|
||||
"name": "wwwww",
|
||||
"description": "",
|
||||
"properties": [],
|
||||
"badges": [],
|
||||
"is_continuous_streamer": 0,
|
||||
"is_new": 0,
|
||||
"user_id": "105481237",
|
||||
"onlive": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"point": 1,
|
||||
"user": {
|
||||
"share_url": "https://www.mirrativ.com/user/103544585",
|
||||
"profile_image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/profile_image/40cbd7501613cf08f45c56704b1a80796413d7ac0f9e06851d7a4ebe6f1fe7de_m.jpeg?1600217414",
|
||||
"name": "ꗼ𝒓𝑦𝒖ꗼ",
|
||||
"description": "俺のファンか仲良い人にしかギフトとかはあげません!まぁ俺にファンなんて居ないけど",
|
||||
"properties": [],
|
||||
"badges": [
|
||||
{
|
||||
"image_url": "https://cdn.mirrativ.com/assets/img/continuous_streamer/ic_badge_master_holiday_L.en.png?v1",
|
||||
"small_image_url": "https://cdn.mirrativ.com/assets/img/continuous_streamer/ic_badge_master_holiday_S.en.png?v1"
|
||||
}
|
||||
],
|
||||
"is_continuous_streamer": 1,
|
||||
"is_new": 0,
|
||||
"catalog_label_image_url": "https://cdn.mirrativ.com/assets/img/continuous_streamer/ic_status_master_holiday_en@3x.png?v5",
|
||||
"user_id": "103544585",
|
||||
"onlive": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"status": {
|
||||
"msg": "",
|
||||
"ok": 1,
|
||||
"error": "",
|
||||
"captcha_url": "",
|
||||
"error_code": 0,
|
||||
"message": ""
|
||||
},
|
||||
"next_cursor": "",
|
||||
"current_cursor": "bW9udGhseToxMDYwNjk5MTY6MjY2NzA0NzMvMA"
|
||||
}
|
||||
|
||||
{
|
||||
"streaming_url_hls": "http://hls-cdn22.mirrativ.com/liveedge/c4d32ce6edec9a37e7b20cff4b656a95714b5b9ee872964d9e435debe74a9518/playlist.m3u8",
|
||||
"is_gift_supported": 1,
|
||||
"live_id": "9LtbLw58uSrzig_NTxutIw",
|
||||
"is_mirrorable": 0,
|
||||
"description": "いつも拝聴ありがとうございます!\nクラッカーは配信が落ちてしまうので、禁止でお願い致しますm(_ _)m\n",
|
||||
"total_viewer_num": 1127,
|
||||
"thumbnail_image_url": "",
|
||||
"is_archive": 0,
|
||||
"is_singing_karaoke": 0,
|
||||
"title": "雑談しながらゲームする!",
|
||||
"max_online_viewer_num": 212,
|
||||
"created_at": 1600194426,
|
||||
"is_live": 1,
|
||||
"started_at": 1600242640,
|
||||
"blur_image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/thumbnail_image_url/64c45462a6dc1113cf984a2bebac27d99cbb9b12c736ee3d104dd4c0c4e086db_m.jpeg?blur=80&1600244617",
|
||||
"preview_blur_image_url": "",
|
||||
"live_mos": null,
|
||||
"thumbnail_blur_image_url": "",
|
||||
"image_url_without_letterbox": "",
|
||||
"diamonds": 0,
|
||||
"joined_live_thumbnail_image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/live_capture/64c45462a6dc1113cf984a2bebac27d99cbb9b12c736ee3d104dd4c0c4e086db_m.jpeg?1600244617",
|
||||
"template_comments": [],
|
||||
"tags": [],
|
||||
"broadcast_host": "online.mirrativ.com",
|
||||
"live_user_key": "",
|
||||
"bcsvr_key": "1abe77db:Cp3UZxJW",
|
||||
"heartbeated_at": 1600244742,
|
||||
"shares": {
|
||||
"twitter": {
|
||||
"maxlength": 84,
|
||||
"card": {
|
||||
"site": "mirrativ.com",
|
||||
"image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/custom_thumbnail/64c45462a6dc1113cf984a2bebac27d99cbb9b12c736ee3d104dd4c0c4e086db_share.jpeg?1600244617",
|
||||
"title": "雑談しながらゲームする!",
|
||||
"description": "🐉そあこ💖爽鱗🐉"
|
||||
},
|
||||
"text": "",
|
||||
"placeholder": "この配信についてひとこと!"
|
||||
},
|
||||
"others": {
|
||||
"text": "雑談しながらゲームする! #プラエデ #ミラティブ #配信 | https://www.mirrativ.com/live/9LtbLw58uSrzig_NTxutIw"
|
||||
},
|
||||
"title": "🐉そあこ💖爽鱗🐉さんの配信を友達にシェアしよう!",
|
||||
"description": "友達が見に来てくれると配信者さんに伝わるよ!"
|
||||
},
|
||||
"is_private": 0,
|
||||
"collab_supported": 1,
|
||||
"sticker_enabled": 0,
|
||||
"collab_has_vacancy": 0,
|
||||
"streaming_key": "c4d32ce6edec9a37e7b20cff4b656a95714b5b9ee872964d9e435debe74a9518",
|
||||
"stamp_num": 0,
|
||||
"linked_live": {
|
||||
"owner_badge_image_url": "https://cdn.mirrativ.com/assets/img/continuous_streamer/ic_badge_super_holiday_S.ja.png?v6",
|
||||
"live_id": "-L6kxuJm_HgJN7aBY5JjYg",
|
||||
"owner_id": "100895240",
|
||||
"owner_image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/profile_image/2a6dab73acec21af7d4d08f53f854e4c3a429d0ba73cd3c8f7618f90ff3c4f9b_m.jpeg?1600184061",
|
||||
"owner_name": "🦔NICO*🦥🥈感謝"
|
||||
},
|
||||
"collab_online_user_num": 0,
|
||||
"share_image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/custom_thumbnail/64c45462a6dc1113cf984a2bebac27d99cbb9b12c736ee3d104dd4c0c4e086db_share.jpeg?1600244617",
|
||||
"broadcast_key": "1abe77db:Cp3UZxJW",
|
||||
"gift_ranking_url": "https://www.mirrativ.com/gift/ranking?live_id=9LtbLw58uSrzig_NTxutIw&obfuscated_user_id=PgIBEgc6jVc",
|
||||
"collab_mos": null,
|
||||
"archive_url_hls": "",
|
||||
"remaining_coins": 0,
|
||||
"ended_at": 0,
|
||||
"sticker_category_ids": [],
|
||||
"online_user_num": 174,
|
||||
"announcement_url": "",
|
||||
"anniversary_bot_comment": "",
|
||||
"is_emomo_wipe_enabled": 0,
|
||||
"share_url": "https://www.mirrativ.com/live/9LtbLw58uSrzig_NTxutIw",
|
||||
"status": {
|
||||
"msg": "",
|
||||
"ok": 1,
|
||||
"error": "",
|
||||
"captcha_url": "",
|
||||
"error_code": 0,
|
||||
"message": ""
|
||||
},
|
||||
"orientation": 2,
|
||||
"app_id": "jp.co.yoozoo.projectyellow",
|
||||
"app_icon_urls": [
|
||||
"https://cdn.mirrativ.com/mirrorman-prod/image/app_icon/999ce961e79bfe6d7fff3db363375a17a112810791a692b8858970efa599ca99.png"
|
||||
],
|
||||
"timeline": [
|
||||
{
|
||||
"app": {
|
||||
"is_my_app": 0,
|
||||
"icon_url": "https://cdn.mirrativ.com/mirrorman-prod/image/app_icon/999ce961e79bfe6d7fff3db363375a17a112810791a692b8858970efa599ca99.png",
|
||||
"store_url": "https://go.onelink.me/app/c8e9133",
|
||||
"app_id": "jp.co.yoozoo.projectyellow",
|
||||
"short_title": "プラエデ",
|
||||
"is_category": 0,
|
||||
"title": "レッド:プライドオブエデン",
|
||||
"id": 3139
|
||||
},
|
||||
"timestamp": 1600242607,
|
||||
"title": "雑談しながらゲームする!"
|
||||
}
|
||||
],
|
||||
"enable_clap": 0,
|
||||
"is_paid_sticker_supported": 0,
|
||||
"announcement_urls": {},
|
||||
"sticker_num": 0,
|
||||
"max_collab_user_num": 3,
|
||||
"comment_num": 145,
|
||||
"owner": {
|
||||
"share_url": "https://www.mirrativ.com/user/104326294",
|
||||
"is_able_continuous_stream_holiday": 1,
|
||||
"profile_image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/profile_image/1046538382ddfccff9b118699ec605cb33cc3c61feb94122f79d5812221e99b5_m.jpeg?1600194531",
|
||||
"birthday_from": 1615561200,
|
||||
"is_birthday_editable": 1,
|
||||
"badges": [
|
||||
{
|
||||
"image_url": "https://cdn.mirrativ.com/assets/img/continuous_streamer/ic_badge_super_holiday_L.ja.png?v6",
|
||||
"small_image_url": "https://cdn.mirrativ.com/assets/img/continuous_streamer/ic_badge_super_holiday_S.ja.png?v6"
|
||||
}
|
||||
],
|
||||
"is_new": 0,
|
||||
"catalog_label_image_url": "https://cdn.mirrativ.com/assets/img/continuous_streamer/ic_status_super_holiday_ja@3x.png?v5",
|
||||
"birthday": "0314",
|
||||
"birthday_to": 1615820399,
|
||||
"name": "🐉そあこ💖爽鱗🐉",
|
||||
"is_birthday": 0,
|
||||
"description": "色んなゲームを17:30に定期配信してます♡ギフト当たった人は欲しい時にDM求む",
|
||||
"birthday_editable_date": "",
|
||||
"properties": [],
|
||||
"is_continuous_streamer": 1,
|
||||
"user_id": "104326294",
|
||||
"live_request_num": "70",
|
||||
"onlive": null
|
||||
},
|
||||
"broadcast_port": 1883,
|
||||
"recommend_sticker_ids": [],
|
||||
"sticker_display_type": 0,
|
||||
"archive_comment_enabled": 0,
|
||||
"streaming_url_edge": "rtmp://edge-210-140-191-149.mirrativ.com:1935/liveedge/c4d32ce6edec9a37e7b20cff4b656a95714b5b9ee872964d9e435debe74a9518",
|
||||
"collab_enabled": 0,
|
||||
"image_url": "https://cdn.mirrativ.com/mirrorman-prod/image/thumbnail_image_url/64c45462a6dc1113cf984a2bebac27d99cbb9b12c736ee3d104dd4c0c4e086db_m.jpeg?1600244617",
|
||||
"orientation_v2": "6"
|
||||
}
|
||||
|
||||
// curl 'https://www.mirrativ.com/api/gift/ranking?obfuscated_user_id=PgIBEgc6jVc&live_id=O5Ia4iX9c5CeZj7DFtg52Q&type=monthly&cursor=' \
|
||||
|
||||
24
utils.go
24
utils.go
@@ -110,16 +110,13 @@ func (adriver *AutoCloseDriver) Close() {
|
||||
// log.Println(string(data))
|
||||
|
||||
killshell := fmt.Sprintf("pkill -9 -P %s", data)
|
||||
// log.Println(killshell)
|
||||
// pkill -f \"port=%d\"
|
||||
// log.Printf(fmt.Sprintf("kill -9 $(lsof -t -i:%d)", port))
|
||||
err = exec.Command("/bin/bash", "-c", killshell).Run()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = exec.Command("/bin/bash", "-c", fmt.Sprintf("kill %s", data)).Run()
|
||||
err = exec.Command("/bin/bash", "-c", fmt.Sprintf("kill -9 %s", data)).Run()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
@@ -134,8 +131,6 @@ func GetChromeDriver() *AutoCloseDriver {
|
||||
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 {
|
||||
@@ -182,23 +177,6 @@ func GetChromeDriver() *AutoCloseDriver {
|
||||
adriver.Port = port
|
||||
adriver.Webdriver = wd
|
||||
|
||||
// runtime.SetFinalizer(adriver, func(obj interface{}) {
|
||||
|
||||
// adriver := obj.(*AutoCloseDriver)
|
||||
// adriver.Webdriver.Close()
|
||||
// adriver.Webdriver.Quit()
|
||||
|
||||
// killshell := fmt.Sprintf("pkill -P `pgrep -f 'port=%d '` && pkill -f 'port=%d '", port, port)
|
||||
// log.Println(killshell)
|
||||
|
||||
// // log.Printf(fmt.Sprintf("kill -9 $(lsof -t -i:%d)", port))
|
||||
// // cmd := exec.Command("sh", "-c", killshell)
|
||||
// // err = cmd.Run()
|
||||
// // if err != nil {
|
||||
// // log.Println(err)
|
||||
// // }
|
||||
// })
|
||||
|
||||
wd.ExecuteScript("windows.navigator.webdriver = undefined", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
Reference in New Issue
Block a user