from html import unescape
from api import models
from api.api_errors import NotFoundError
from api.resources.charts import ChartResource
from . import AuthenticatedResource as Resource
from flask import request
from tracker import db
def _unescape_title(vid_dict: dict):
vid_dict['title'] = unescape(vid_dict['title'])
return vid_dict
class YouTube(ChartResource):
def get(self):
return {
"dataMatrixColumns": [
"view_count",
"like_count",
"dislike_count",
"favorite_count",
"comment_count",
],
"videos": [_unescape_title(v) for v in db.execute_to_dicts("""
select
yt_videos.ytid,
first(yt_videos.published) published,
first(yt_videos.title) title,
first(ch.name) as "channel_name",
jsonb_agg_uniq(
jsonb_build_array(
to_stat_date(as_of::date),
view_count,
like_count,
dislike_count,
favorite_count,
comment_count
) order by as_of
) as "dataMatrix"
from yt_videos
join yt_channel_videos cv on cv.video_ytid = yt_videos.ytid
join yt_channels ch on ch.ytid = cv.channel_ytid
join users_yt_channels uyc on uyc.ytid = ch.ytid and username = :username
join yt_video_statistics stats on stats.video_ytid = yt_videos.ytid
and CURRENT_DATE - stats.as_of::date in (0,1,2,3,5,6,10,11,12,30,31,32,60,61,62)
group by 1 -- Potentially we get multple statistics on the same day
""", params=dict(username=self.user.name), read_replica=True)],
}
def post(self):
filters = self.get_filters(maxPublishedDaysAgo=365, minPublishedDaysAgo=0)
and_channel_clause = ""
if filters.get('channelIds'):
and_channel_clause = " and ch.ytid = any(:channelIds) "
sql_query = """
select
yt_videos.ytid,
first(yt_videos.published) published,
first(yt_videos.title) title,
first(ch.name) as "channel_name",
first(ch.ytid) as "channel_ytid",
jsonb_agg_uniq(
jsonb_build_array(
to_stat_date(as_of::date),
view_count,
like_count,
dislike_count,
favorite_count,
comment_count
) order by as_of
) as "dataMatrix"
from yt_videos
join yt_channel_videos cv on cv.video_ytid = yt_videos.ytid
join yt_channels ch on ch.ytid = cv.channel_ytid
join users_yt_channels uyc on uyc.ytid = ch.ytid and username = :username {and_channel_clause}
join yt_video_statistics stats
on stats.video_ytid = yt_videos.ytid
and stats.as_of > now() - interval '33 days'
and CURRENT_DATE - stats.as_of::date in (0,1,2,3,5,6,10,11,12,30,31,32)
where yt_videos.published
between (now() - (:maxPublishedDaysAgo * interval '1 day'))
and (now() - (:minPublishedDaysAgo * interval '1 day'))
group by 1
""".format(and_channel_clause=and_channel_clause)
return {
"dataMatrixColumns": [
"view_count",
"like_count",
"dislike_count",
"favorite_count",
"comment_count",
],
"videos": [_unescape_title(v) for v in db.execute_to_dicts(sql_query, params=dict(filters, username=self.user.name), read_replica=True)],
}
class VideoDetail(Resource):
def get(self, ytid):
result = next(db.execute_to_dicts("""
select
video_ytid as ytid,
jsonb_agg_uniq_by_first_item(
jsonb_build_array(
to_stat_date(as_of::date),
view_count,
like_count,
dislike_count,
favorite_count,
comment_count
) order by as_of
) as "dataMatrix"
from yt_video_statistics
where video_ytid = :ytid
group by 1;
""", params=dict(ytid=ytid)), None)
if not result:
raise NotFoundError("No video found with ytid: {}".format(ytid))
models.youtube_videos([ytid])
return dict(
next(models.youtube_videos([ytid]))['video'],
dataMatrix=result['dataMatrix'] or []
)