Add video durations and view counts

This commit is contained in:
Alessio 2021-12-24 16:26:34 -05:00
parent f73ef57cf2
commit 28e139a3e4
8 changed files with 57 additions and 9 deletions

View File

@ -33,13 +33,14 @@ func (p Profile) SaveImage(img scraper.Image) error {
*/ */
func (p Profile) SaveVideo(vid scraper.Video) error { func (p Profile) SaveVideo(vid scraper.Video) error {
_, err := p.DB.Exec(` _, err := p.DB.Exec(`
insert into videos (id, tweet_id, width, height, remote_url, local_filename, thumbnail_remote_url, thumbnail_local_filename, is_downloaded, is_gif) insert into videos (id, tweet_id, width, height, remote_url, local_filename, thumbnail_remote_url, thumbnail_local_filename, duration, view_count, is_downloaded, is_gif)
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
on conflict do update on conflict do update
set is_downloaded=(is_downloaded or ?) set is_downloaded=(is_downloaded or ?),
view_count=max(view_count, ?)
`, `,
vid.ID, vid.TweetID, vid.Width, vid.Height, vid.RemoteURL, vid.LocalFilename, vid.ThumbnailRemoteUrl, vid.ThumbnailLocalPath, vid.IsDownloaded, vid.IsGif, vid.ID, vid.TweetID, vid.Width, vid.Height, vid.RemoteURL, vid.LocalFilename, vid.ThumbnailRemoteUrl, vid.ThumbnailLocalPath, vid.Duration, vid.ViewCount, vid.IsDownloaded, vid.IsGif,
vid.IsDownloaded, vid.IsDownloaded, vid.ViewCount,
) )
return err return err
} }
@ -112,7 +113,7 @@ func (p Profile) GetImagesForTweet(t scraper.Tweet) (imgs []scraper.Image, err e
* Get the list of videos for a tweet * Get the list of videos for a tweet
*/ */
func (p Profile) GetVideosForTweet(t scraper.Tweet) (vids []scraper.Video, err error) { func (p Profile) GetVideosForTweet(t scraper.Tweet) (vids []scraper.Video, err error) {
stmt, err := p.DB.Prepare("select id, width, height, remote_url, local_filename, thumbnail_remote_url, thumbnail_local_filename, is_downloaded, is_gif from videos where tweet_id=?") stmt, err := p.DB.Prepare("select id, width, height, remote_url, local_filename, thumbnail_remote_url, thumbnail_local_filename, duration, view_count, is_downloaded, is_gif from videos where tweet_id=?")
if err != nil { if err != nil {
return return
} }
@ -123,7 +124,7 @@ func (p Profile) GetVideosForTweet(t scraper.Tweet) (vids []scraper.Video, err e
} }
var vid scraper.Video var vid scraper.Video
for rows.Next() { for rows.Next() {
err = rows.Scan(&vid.ID, &vid.Width, &vid.Height, &vid.RemoteURL, &vid.LocalFilename, &vid.ThumbnailRemoteUrl, &vid.ThumbnailLocalPath, &vid.IsDownloaded, &vid.IsGif) err = rows.Scan(&vid.ID, &vid.Width, &vid.Height, &vid.RemoteURL, &vid.LocalFilename, &vid.ThumbnailRemoteUrl, &vid.ThumbnailLocalPath, &vid.Duration, &vid.ViewCount, &vid.IsDownloaded, &vid.IsGif)
if err != nil { if err != nil {
return return
} }

View File

@ -131,7 +131,7 @@ func TestSaveAndLoadVideo(t *testing.T) {
} }
/** /**
* Change an Image, save the changes, reload it, and check if it comes back the same * Change an Video, save the changes, reload it, and check if it comes back the same
*/ */
func TestModifyVideo(t *testing.T) { func TestModifyVideo(t *testing.T) {
profile_path := "test_profiles/TestMediaQueries" profile_path := "test_profiles/TestMediaQueries"
@ -145,6 +145,7 @@ func TestModifyVideo(t *testing.T) {
} }
vid.IsDownloaded = true vid.IsDownloaded = true
vid.ViewCount = 23000
// Save the changes // Save the changes
err := profile.SaveVideo(vid) err := profile.SaveVideo(vid)

View File

@ -128,6 +128,8 @@ create table videos (rowid integer primary key,
local_filename text not null unique, local_filename text not null unique,
thumbnail_remote_url text not null default "missing", thumbnail_remote_url text not null default "missing",
thumbnail_local_filename text not null default "missing", thumbnail_local_filename text not null default "missing",
duration integer not null default 0,
view_count integer not null default 0,
is_gif boolean default 0, is_gif boolean default 0,
is_downloaded boolean default 0, is_downloaded boolean default 0,

View File

@ -94,6 +94,8 @@ func create_video_from_id(id int) scraper.Video {
LocalFilename: filename, LocalFilename: filename,
ThumbnailRemoteUrl: filename, ThumbnailRemoteUrl: filename,
ThumbnailLocalPath: filename, ThumbnailLocalPath: filename,
Duration: 10000,
ViewCount: 200,
IsDownloaded: false, IsDownloaded: false,
IsGif: false, IsGif: false,
} }

View File

@ -8,7 +8,7 @@ import (
) )
const ENGINE_DATABASE_VERSION = 4 const ENGINE_DATABASE_VERSION = 5
type VersionMismatchError struct { type VersionMismatchError struct {
@ -56,6 +56,8 @@ var MIGRATIONS = []string{
insert into tombstone_types (rowid, short_name, tombstone_text) values (5, 'violated', 'This Tweet violated the Twitter Rules'), (6, 'no longer exists', 'This Tweet is from an account that no longer exists')`, insert into tombstone_types (rowid, short_name, tombstone_text) values (5, 'violated', 'This Tweet violated the Twitter Rules'), (6, 'no longer exists', 'This Tweet is from an account that no longer exists')`,
`alter table videos add column thumbnail_remote_url text not null default "missing"; `alter table videos add column thumbnail_remote_url text not null default "missing";
alter table videos add column thumbnail_local_filename text not null default "missing"`, alter table videos add column thumbnail_local_filename text not null default "missing"`,
`alter table videos add column duration integer not null default 0;
alter table videos add column view_count integer not null default 0`,
} }
/** /**

View File

@ -35,11 +35,17 @@ type APIExtendedMedia struct {
Type string `json:"type"` Type string `json:"type"`
VideoInfo struct { VideoInfo struct {
Variants SortableVariants `json:"variants"` Variants SortableVariants `json:"variants"`
Duration int `json:"duration_millis"`
} `json:"video_info"` } `json:"video_info"`
OriginalInfo struct { OriginalInfo struct {
Width int `json:"width"` Width int `json:"width"`
Height int `json:"height"` Height int `json:"height"`
} `json:"original_info"` } `json:"original_info"`
Ext struct {
MediaStats struct {
R interface{} `json:"r"`
} `json:"mediaStats"`
} `json:"ext"`
} }
type APICard struct { type APICard struct {

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"path" "path"
"reflect"
) )
type VideoID int64 type VideoID int64
@ -21,6 +22,8 @@ type Video struct {
ThumbnailRemoteUrl string ThumbnailRemoteUrl string
ThumbnailLocalPath string ThumbnailLocalPath string
Duration int // milliseconds
ViewCount int
IsDownloaded bool IsDownloaded bool
IsGif bool IsGif bool
@ -30,6 +33,25 @@ func ParseAPIVideo(apiVideo APIExtendedMedia, tweet_id TweetID) Video {
variants := apiVideo.VideoInfo.Variants variants := apiVideo.VideoInfo.Variants
sort.Sort(variants) sort.Sort(variants)
var view_count int
r := apiVideo.Ext.MediaStats.R
switch r.(type) {
case string:
view_count = 0
case map[string]interface{}:
OK_entry, ok := r.(map[string]interface{})["ok"]
if !ok {
panic("No 'ok' value found in the R!")
}
view_count_str, ok := OK_entry.(map[string]interface{})["viewCount"]
view_count = int_or_panic(view_count_str.(string))
if !ok {
panic("No 'viewCount' value found in the OK!")
}
}
local_filename := fmt.Sprintf("%d.mp4", tweet_id) local_filename := fmt.Sprintf("%d.mp4", tweet_id)
return Video{ return Video{
@ -42,6 +64,8 @@ func ParseAPIVideo(apiVideo APIExtendedMedia, tweet_id TweetID) Video {
ThumbnailRemoteUrl: apiVideo.MediaURLHttps, ThumbnailRemoteUrl: apiVideo.MediaURLHttps,
ThumbnailLocalPath: path.Base(apiVideo.MediaURLHttps), ThumbnailLocalPath: path.Base(apiVideo.MediaURLHttps),
Duration: apiVideo.VideoInfo.Duration,
ViewCount: view_count,
IsDownloaded: false, IsDownloaded: false,
IsGif: apiVideo.Type == "animated_gif", IsGif: apiVideo.Type == "animated_gif",

View File

@ -53,6 +53,16 @@ func TestParseAPIVideo(t *testing.T) {
if video.ThumbnailLocalPath != expected_thumbnail_filename { if video.ThumbnailLocalPath != expected_thumbnail_filename {
t.Errorf("Expected %q, got %q", expected_thumbnail_filename, video.ThumbnailLocalPath) t.Errorf("Expected %q, got %q", expected_thumbnail_filename, video.ThumbnailLocalPath)
} }
expected_view_count := 275952
if video.ViewCount != expected_view_count {
t.Errorf("Expected view count %d, got %d", expected_view_count, video.ViewCount)
}
expected_duration := 88300
if video.Duration != expected_duration {
t.Errorf("Expected duration %d, got %d", expected_duration, video.Duration)
}
if video.IsDownloaded { if video.IsDownloaded {
t.Errorf("Expected it not to be downloaded, but it was") t.Errorf("Expected it not to be downloaded, but it was")
} }