// GetVideo returns a video or an error // // Direct link: // curl 'http://hcm.nhac.vui.vn/ajax/nghe_bai_hat/download_320k/472092' -H 'Cookie: pageCookie=13; ACCOUNT_ID=965257; token=3f363de2c081a3a3a685b1033e6f03b1%7C52ab4c37;' -v func GetVideo(id dna.Int) (*Video, error) { var video *Video = NewVideo() video.Id = id c := make(chan bool, 2) go func() { c <- <-getVideoXML(video) }() go func() { c <- <-getVideoFromMainPage(video) }() for i := 0; i < 2; i++ { <-c } // Check how many bits in ResolutionFlags have value 1 var count uint32 = 0 for i := uint32(0); i < 5; i++ { if (int(video.ResolutionFlags)>>i)&1 == 1 { count += 1 } } if video.Links.Length() == 0 { return nil, errors.New(dna.Sprintf("Chacha - Video %v: Link not found", video.Id).String()) } else if dna.Int(count) != video.Links.Length() { return nil, errors.New(dna.Sprintf("Chacha - Video %v: Video Resolution flags and links do not match", video.Id).String()) } else { video.Checktime = time.Now() return video, nil } }
func (apiVideo *APIVideo) FillVideo(video *Video) { video.Id = apiVideo.Id video.Key = apiVideo.Key video.Title = apiVideo.Title video.Image = apiVideo.Thumbnail // Image is for small image video.Thumbnail = apiVideo.Image // Thumbnail is for the large, kinda opposite // Getting dateCreated datecreatedArr := video.Thumbnail.FindAllStringSubmatch(`/([0-9]+)_[0-9]+\..+$`, -1) if len(datecreatedArr) > 0 { // Log(int64(datecreatedArr[0][1].ToInt())) video.DateCreated = time.Unix(int64(datecreatedArr[0][1].ToInt()/1000), 0) } else { dateCreatedArr := video.Thumbnail.FindAllStringSubmatch(`/?(\d{4}/\d{2}/\d{2})`, -1) if len(dateCreatedArr) > 0 { year := dateCreatedArr[0][1].FindAllStringSubmatch(`(\d{4})/\d{2}/\d{2}`, -1)[0][1].ToInt() month := dateCreatedArr[0][1].FindAllStringSubmatch(`\d{4}/(\d{2})/\d{2}`, -1)[0][1].ToInt() day := dateCreatedArr[0][1].FindAllStringSubmatch(`\d{4}/\d{2}/(\d{2})`, -1)[0][1].ToInt() video.DateCreated = time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, time.UTC) } } video.Artists = apiVideo.Artist.Split(",").SplitWithRegexp(" & ") durationArr := apiVideo.Time.Split(":") switch durationArr.Length() { case 2: duration, err := time.ParseDuration((durationArr[0] + "m" + durationArr[1] + "s").String()) if err == nil { video.Duration = dna.Int(int(duration.Seconds())) } else { dna.Log("Critical error: cannot parse duration of video id:", video.Id) dna.Log("\n\n\n") panic("Cannot parse duration") } case 3: duration, err := time.ParseDuration((durationArr[0] + "h" + durationArr[1] + "m" + durationArr[2] + "s").String()) if err == nil { video.Duration = dna.Int(int(duration.Seconds())) } else { dna.Log("Critical error: cannot parse duration of video id:", video.Id) dna.Log("\n\n\n") panic("Cannot parse duration") } default: dna.Log("Critical error: Unknown duration format of video id:", video.Id) dna.Log("\n\n\n") panic("Cannot parse duration") } video.Artistid = apiVideo.Artistid video.Likes = apiVideo.Likes video.Plays = apiVideo.Plays video.LinkShare = apiVideo.Linkshare video.StreamUrl = apiVideo.StreamUrl video.Type = apiVideo.ObjType }
// ToAlbum converts APIAlbum to Album type. func (apiAlbum *APIAlbum) ToAlbum() *Album { album := NewAlbum() album.Id = apiAlbum.Id keyArr := apiAlbum.Url.FindAllStringSubmatch(`.+/(.+?)\.html`, 1) if len(keyArr) > 0 { album.Key = keyArr[0][1] } album.Title = apiAlbum.Title album.Artists = apiAlbum.Artists.Split(" ft ").FilterEmpty() album.Plays = apiAlbum.Plays songids := dna.IntArray{} for _, song := range apiAlbum.SongList { songids.Push(song.Id) } album.Songids = songids album.Nsongs = dna.Int(len(apiAlbum.SongList)) album.Description = "" album.Coverart = apiAlbum.Coverart dateCreatedArr := album.Coverart.FindAllStringSubmatch(`/?(\d{4}/\d{2}/\d{2})`, -1) if len(dateCreatedArr) > 0 { year := dateCreatedArr[0][1].FindAllStringSubmatch(`(\d{4})/\d{2}/\d{2}`, -1)[0][1].ToInt() month := dateCreatedArr[0][1].FindAllStringSubmatch(`\d{4}/(\d{2})/\d{2}`, -1)[0][1].ToInt() day := dateCreatedArr[0][1].FindAllStringSubmatch(`\d{4}/\d{2}/(\d{2})`, -1)[0][1].ToInt() album.DateCreated = time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, time.UTC) } album.Checktime = time.Now() return album }
// getSongFromXML returns values from url: http://nhacso.net/flash/song/xnl/1/id/ func getSongFromXML(song *Song) <-chan bool { channel := make(chan bool, 1) go func() { link := "http://nhacso.net/flash/song/xnl/1/id/" + GetKey(song.Id) result, err := http.Get(link) if err == nil { song.Title = getValueXML(&result.Data, "name", 1).Trim() song.Artists = getValueXML(&result.Data, "artist", 0).ToStringArray().SplitWithRegexp("\\|\\|").SplitWithRegexp(" / ").SplitWithRegexp(" - ") song.Artistid = getValueXML(&result.Data, "artistlink", 0).ReplaceWithRegexp("\\.html", "").ReplaceWithRegexp(`^.+-`, "").ToInt() authors := getValueXML(&result.Data, "author", 0) if !authors.IsBlank() { song.Authors = authors.ToStringArray().SplitWithRegexp("\\|\\|").SplitWithRegexp(" / ").SplitWithRegexp(" - ") song.Authorid = getValueXML(&result.Data, "authorlink", 0).ReplaceWithRegexp(`\.html`, "").ReplaceWithRegexp(`^.+-`, "").ToInt() } duration := result.Data.FindAllString("<totalTime.+totalTime>", 1) if duration.Length() > 0 { song.Duration = duration[0].RemoveHtmlTags("").Trim().ToInt() } song.Link = getValueXML(&result.Data, "mp3link", 0) if song.Title != "" && song.Link != "/" { ts := song.Link.FindAllString(`\/[0-9]+_`, 1)[0].ReplaceWithRegexp(`\/`, "").ReplaceWithRegexp(`_`, "") unix := ts.ToInt().ToFloat() * dna.Float(math.Pow10(13-len(ts))) song.DateCreated = dna.Int(int64(unix) / 1000).ToTime() song.DateUpdated = time.Now() } } channel <- true }() return channel }
// UpdateNhacso gets lastest items from nhacso.com. // The update process goes through 7 steps: // Step 1: Initalizing db connection, loading site config and state handler. // Step 2: Updating new songs. // Step 3: Updating new albums. // Step 4: Updating new videos. // Step 5: Updating catagories of new songs. // Step 6: Updating catagories of new albums. // Step 7: Recovering failed sql statements. func UpdateNhacso() { db, err := sqlpg.Connect(sqlpg.NewSQLConfig(SqlConfigPath)) dna.PanicError(err) siteConf, err := LoadSiteConfig("ns", SiteConfigPath) dna.PanicError(err) // update song state := NewStateHandler(new(ns.Song), siteConf, db) Update(state) // update album state = NewStateHandler(new(ns.Album), siteConf, db) Update(state) // update video state = NewStateHandler(new(ns.Video), siteConf, db) Update(state) r := NewRange(0, dna.Int(len(*ns.SongGenreList))*ns.LastNPages-1) siteConf.NConcurrent = 10 state = NewStateHandlerWithRange(new(ns.SongCategory), r, siteConf, db) Update(state) state = NewStateHandlerWithRange(new(ns.AlbumCategory), r, siteConf, db) Update(state) RecoverErrorQueries(SqlErrorLogPath, db) time.Sleep(3 * time.Second) CountDown(3*time.Second, QuittingMessage, EndingMessage) db.Close() }
// GetMovie returns a movie or an error. func GetMovie(id dna.Int) (*Movie, error) { var movie *Movie = NewMovie() movie.Id = id c := make(chan bool, 1) go func() { c <- <-getMovieFromPage(movie) }() for i := 0; i < 1; i++ { <-c } if movie.Title == "" && movie.AnotherTitle == "" { return nil, errors.New(dna.Sprintf("Hdviet - Movie %v: Not available", movie.Id).String()) } else { // Generating EpisodeKeyList if movie.IsSeries == false { EpisodeKeyList.Push(movie.Id * 1000) } else { for i := dna.Int(1); i <= movie.CurrentEps; i++ { EpisodeKeyList.Push(ToEpisodeKey(movie.Id, i)) } } return movie, nil } // if movie.Link == "" || movie.Link == "/" { // return nil, errors.New(fmt.Sprintf("Nhacso - Movie %v: Mp3 link not found", movie.Id)) // } else { // movie.Checktime = time.Now() // return movie, nil // } }
// RecoverSQLLogError re-executes failed sql queries in sql error log file from specified path. // It returns the number of failed -reexec queries, and new failed // queries will be written to the file // // The format of error file is: // Error description - $$$error$$$SQL_QUERY$$$error$$$ // Therefore only get statements enclosed by special `$$$error$$$` func RecoverSQLLogError(sqlErrFilePath dna.String, db *sqlpg.DB) dna.Int { var errCount = 0 var errStrings = dna.StringArray{} b, err := ioutil.ReadFile(sqlErrFilePath.String()) if err != nil { panic(err) } data := dna.String(string(b)) // dna.Log("\n", data.Length()) sqlArr := data.FindAllString(`(?mis)\$\$\$error\$\$\$.+?\$\$\$error\$\$\$`, -1) // dna.Log("\nTOTAL SQL STATEMENTS FOUND:", sqlArr.Length()) for _, val := range sqlArr { sqlStmtArr := val.FindAllStringSubmatch(`(?mis)\$\$\$error\$\$\$(.+?)\$\$\$error\$\$\$`, -1) if len(sqlStmtArr) > 0 { _, err := db.Exec(sqlStmtArr[0][1].String()) if err != nil { if dna.String(err.Error()).Contains(`duplicate key value violates unique constraint`) == false { errCount += 1 errStrings.Push("$$$error$$$" + sqlStmtArr[0][1] + "$$$error$$$") } } } } if errCount == 0 { err = ioutil.WriteFile(sqlErrFilePath.String(), []byte{}, 0644) } else { err = ioutil.WriteFile(sqlErrFilePath.String(), []byte(errStrings.Join("\n").String()), 0644) } if err != nil { panic(err) } return dna.Int(errCount) }
// Init implements item.Item interface. func (alca *AlbumCategory) Init(v interface{}) { var n dna.Int var NGenres dna.Int = dna.Int(len((*SongGenreList))) // The total of genres switch v.(type) { case int: n = dna.Int(v.(int)) case dna.Int: n = v.(dna.Int) default: panic("Interface v has to be int") } genreIndex := dna.Int(n / LastNPages) if genreIndex >= NGenres { genreIndex = NGenres - 1 } alca.Genre = (*SongGenreList)[genreIndex] alca.Page = n%LastNPages + 1 }
// Init implements item.Item interface. // It sets EpisodeKey func (eu *EpUpdater) Init(v interface{}) { switch v.(type) { case int: eu.EpId, eu.CurrentEps = ToMovieIdAndEpisodeId(dna.Int(v.(int))) case dna.Int: eu.EpId, eu.CurrentEps = ToMovieIdAndEpisodeId(v.(dna.Int)) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (users *Users) Init(v interface{}) { switch v.(type) { case int: users.InitialId = dna.Int(v.(int)) case dna.Int: users.InitialId = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (album *Album) Init(v interface{}) { switch v.(type) { case int: album.Id = dna.Int(v.(int)) case dna.Int: album.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (episode *Episode) Init(v interface{}) { switch v.(type) { case int: episode.MovieId, episode.EpId = ToMovieIdAndEpisodeId(dna.Int(v.(int))) case dna.Int: episode.MovieId, episode.EpId = ToMovieIdAndEpisodeId(v.(dna.Int)) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (tv *TV) Init(v interface{}) { switch v.(type) { case int: tv.Id = dna.Int(v.(int)) case dna.Int: tv.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (apiSong *APIFullSong) Init(v interface{}) { switch v.(type) { case int: apiSong.Track.Id = dna.Int(v.(int)) case dna.Int: apiSong.Track.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (movie *Movie) Init(v interface{}) { switch v.(type) { case int: movie.Id = dna.Int(v.(int)) case dna.Int: movie.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (lyric *Lyric) Init(v interface{}) { switch v.(type) { case int: lyric.Id = dna.Int(v.(int)) case dna.Int: lyric.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (artist *Artist) Init(v interface{}) { switch v.(type) { case int: artist.Id = dna.Int(v.(int)) case dna.Int: artist.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
func (subject *Subject) Init(v interface{}) { switch v.(type) { case int: subject.Id = dna.Int(v.(int)) case dna.Int: subject.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (video *Video) Init(v interface{}) { switch v.(type) { case int: video.Id = dna.Int(v.(int)) case dna.Int: video.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (sf *APISongFreaksTrack) Init(v interface{}) { switch v.(type) { case int: sf.Id = dna.Int(v.(int)) case dna.Int: sf.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (song *Song) Init(v interface{}) { switch v.(type) { case int: song.Id = dna.Int(v.(int)) case dna.Int: song.Id = v.(dna.Int) default: panic("Interface v has to be int") } }
// GetEncodedKey gets an encoded key used for XML file or a direct link func (song *Song) GetEncodedKey(bitrate Bitrate) dna.String { var temp dna.IntArray if bitrate == Lossless { temp = dna.IntArray{11, 12, 13, 13, 11, 14, 13, 13} } else { temp = dna.Int(bitrate).ToString().Split("").ToIntArray() } tailArray := dna.IntArray{10}.Concat(temp).Concat(dna.IntArray{10, 2, 0, 1, 0}) return getCipherText(GetId(song.Key), tailArray) }
func (apiAlbum *APIAlbum) FillAlbum(album *Album) { var ( nSongs, nVideos dna.Int = 0, 0 ) album.Id = apiAlbum.Id album.Key = apiAlbum.Key album.Title = apiAlbum.Title album.Artists = apiAlbum.Artist.Split(", ") album.Topics = apiAlbum.Genre.ToStringArray() album.Likes = apiAlbum.Likes album.Plays = apiAlbum.Plays ids := dna.IntArray{} for _, song := range apiAlbum.Listsong { if isSongFormat(song.StreamUrl) == true { nSongs += 1 } if isVideoFormat(song.StreamUrl) == true { nVideos += 1 } ids.Push(song.Id) } // dna.Log("NSONGS AND VIDEOS:", nSongs, nVideos) album.Songids = ids album.Nsongs = dna.Int(len(apiAlbum.Listsong)) album.Description = apiAlbum.Description album.Coverart = apiAlbum.Coverart album.LinkShare = apiAlbum.Linkshare switch { case nSongs == album.Nsongs: album.Type = "PLAYLIST_SONG" case nVideos == album.Nsongs: album.Type = "PLAYLIST_VIDEO" case nVideos+nSongs == album.Nsongs: album.Type = "PLAYLIST_MIXED" default: album.Type = "PLAYLIST" } datecreatedArr := album.Coverart.FindAllStringSubmatch(`/([0-9]+)[_500]*\..+$`, -1) if len(datecreatedArr) > 0 { // Log(int64(datecreatedArr[0][1].ToInt())) album.DateCreated = time.Unix(int64(datecreatedArr[0][1].ToInt()/1000), 0) } else { dateCreatedArr := album.Coverart.FindAllStringSubmatch(`/?(\d{4}/\d{2}/\d{2})`, -1) if len(dateCreatedArr) > 0 { year := dateCreatedArr[0][1].FindAllStringSubmatch(`(\d{4})/\d{2}/\d{2}`, -1)[0][1].ToInt() month := dateCreatedArr[0][1].FindAllStringSubmatch(`\d{4}/(\d{2})/\d{2}`, -1)[0][1].ToInt() day := dateCreatedArr[0][1].FindAllStringSubmatch(`\d{4}/\d{2}/(\d{2})`, -1)[0][1].ToInt() album.DateCreated = time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, time.UTC) } } album.Checktime = time.Now() }
func (song *Song) Save(db *sqlpg.DB) error { insertStmt := sqlpg.GetInsertStatement("mlsongs", song, false) + "\n" mutex.Lock() n, err := SongFile.WriteString(insertStmt.String()) TotalBytes += dna.Int(n) mutex.Unlock() if err == nil { return nil } else { return err } }
// DecodeEncodedKey decodes an encoded key to a key func DecodeEncodedKey(key dna.String) dna.String { var y dna.IntArray = key[5:15].Split("").Map(func(v dna.String, i dna.Int) dna.Int { for j, val := range c { for _, char := range val.Split("") { if char == v { return dna.Int(j) } } } return -1 }).([]dna.Int) return GetKey(y.ToString().ToInt() + 307843200) }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (album *Album) Init(v interface{}) { switch v.(type) { case int: album.Id = dna.Int(v.(int)) case dna.Int: album.Id = v.(dna.Int) // case string: // album.Key = dna.String(v.(string)) // case dna.String: // album.Key = v.(String) default: panic("Interface v has to be int") } }
// Init implements item.Item interface. // It sets Id or key. // dna.Interface v has type int or dna.Int, it calls Id field. // Otherwise if v has type string or dna.String, it calls Key field. func (song *Song) Init(v interface{}) { switch v.(type) { case int: song.Id = dna.Int(v.(int)) case dna.Int: song.Id = v.(dna.Int) // case string: // song.Key = dna.String(v.(string)) // case dna.String: // song.Key = v.(String) default: panic("Interface v has to be int") } }
// Get impliments getting site with basic properties. // Enable gzip, deflat by default to reduce network data, redirect to new location from response. // It returns data (String type) and error // if err is nil then data is "" (empty). func Get(url dna.String) (*Result, error) { req, err := http.NewRequest("GET", url.ToPrimitiveValue(), nil) req.Header = DefaulHeader // req.Header.Add("Accept-Encoding", "gzip,deflate") // req.Header.Add("Accept-Language", "en-US,en") // req.Header.Add("Cache-Control", "max-age=0") // req.Header.Add("Connection", "keep-alive") req.Header.Add("Host", url.ToPrimitiveValue()) // req.Header.Add("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)") // req.Header.Add("Cookie", "") // dna.Log(req.Header) res, err := client.Do(req) if err != nil { return new(Result), err } var data []byte var myErr error switch res.Header.Get("Content-Encoding") { case "gzip": var reader io.ReadCloser reader, err := gzip.NewReader(res.Body) if err != nil { return new(Result), err } data, myErr = ioutil.ReadAll(reader) reader.Close() case "deflate": // Logv("sdsafsd") reader, err := zlib.NewReader(res.Body) if err != nil { return new(Result), err } data, myErr = ioutil.ReadAll(reader) reader.Close() default: data, myErr = ioutil.ReadAll(res.Body) } if myErr != nil { return new(Result), myErr } res.Body.Close() return NewResult(dna.Int(res.StatusCode), dna.String(res.Status), res.Header, dna.String(data)), nil }
// Tick changes its values when an item is being processed. // // * hasError: determines whether a processed item is successful or not. func (c *Counter) Tick(hasError dna.Bool) { c.mu.Lock() if hasError == true { c.Fail += 1 c.CFail += 1 } else { c.Pass += 1 c.CFail = 0 } c.Count += 1 c.ElapsedTime = time.Since(c.startingTime) if c.ElapsedTime/time.Second > 0 { c.Speed = dna.Int(int64(c.Count) / int64(c.ElapsedTime/time.Second)) } c.mu.Unlock() }
func Post(url dna.String, bodyStr dna.String) (*Result, error) { client := &http.Client{} // dna.Log(bodyStr) req, err := http.NewRequest("POST", url.String(), strings.NewReader(bodyStr.String())) req.Header = DefaulHeader req.Header.Add("Host", url.ToPrimitiveValue()) res, err := client.Do(req) if err != nil { return new(Result), err } var data []byte var myErr error switch res.Header.Get("Content-Encoding") { case "gzip": var reader io.ReadCloser reader, err := gzip.NewReader(res.Body) if err != nil { return new(Result), err } data, myErr = ioutil.ReadAll(reader) reader.Close() case "deflate": // Logv("sdsafsd") reader, err := zlib.NewReader(res.Body) if err != nil { return new(Result), err } data, myErr = ioutil.ReadAll(reader) reader.Close() default: data, myErr = ioutil.ReadAll(res.Body) } if myErr != nil { return new(Result), myErr } res.Body.Close() return NewResult(dna.Int(res.StatusCode), dna.String(res.Status), res.Header, dna.String(data)), nil }