Add video durations and view counts
This commit is contained in:
parent
f73ef57cf2
commit
28e139a3e4
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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`,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 {
|
||||||
|
@ -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",
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user