1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/social_youtube/models/social_live_post.py
2024-12-10 09:04:09 +07:00

138 lines
5.6 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import requests
from odoo import _, fields, models, tools
from werkzeug.urls import url_join
class SocialLivePostYoutube(models.Model):
_inherit = 'social.live.post'
youtube_video_id = fields.Char(related='post_id.youtube_video_id')
def _refresh_statistics(self):
super(SocialLivePostYoutube, self)._refresh_statistics()
youtube_accounts = self.env['social.account'].search([('media_type', '=', 'youtube')])
# 1. build various data structures we are going to need
all_existing_posts = self.env['social.live.post'].sudo().search([
('account_id', 'in', youtube_accounts.ids),
('youtube_video_id', '!=', False)
])
posts_per_account = dict.fromkeys(youtube_accounts.ids, self.env['social.live.post'])
for existing_post in all_existing_posts:
posts_per_account[existing_post.account_id.id] |= existing_post
existing_live_posts_by_youtube_video_id = {
live_post.youtube_video_id: live_post for live_post in all_existing_posts
}
# 2. make one batch of requests per account to fetch youtube videos
youtube_videos = []
for account in youtube_accounts:
account._refresh_youtube_token()
video_endpoint_url = url_join(self.env['social.media']._YOUTUBE_ENDPOINT, "youtube/v3/videos")
youtube_video_ids = posts_per_account[account.id].mapped('youtube_video_id')
YOUTUBE_BATCH_SIZE = 50 # can only fetch videos 50 by 50 maximum, limited by YouTube API
for video_ids_batch in tools.split_every(YOUTUBE_BATCH_SIZE, youtube_video_ids):
result = requests.get(video_endpoint_url,
params={
'id': ','.join(video_ids_batch),
'access_token': account.youtube_access_token,
'part': 'statistics',
'maxResults': YOUTUBE_BATCH_SIZE,
},
timeout=5
)
if not result.ok:
account._action_disconnect_accounts(result.json())
break
youtube_videos += result.json().get('items')
# 3. update live post based on video statistics
for video in youtube_videos:
video_stats = video['statistics']
existing_live_posts_by_youtube_video_id.get(video['id']).write({
'engagement': sum(int(video_stats.get(key, 0)) for key in [
'likeCount',
'viewCount',
'commentCount',
'dislikeCount',
'favoriteCount'
]),
})
def _post(self):
youtube_live_posts = self._filter_by_media_types(['youtube'])
super(SocialLivePostYoutube, (self - youtube_live_posts))._post()
for live_post in youtube_live_posts:
live_post._post_youtube()
def _post_youtube(self):
""" Will simply mark the already uploaded video as 'publicly available'. """
self.ensure_one()
self.account_id._refresh_youtube_token()
youtube_description = self.post_id.youtube_description
if youtube_description:
# shorten and UTMize links in YouTube description
# we only do that for the content we put on YouTube, the "message" field remains
# untouched to avoid confusing the end user
youtube_description = self.env['mail.render.mixin'].sudo()._shorten_links_text(
youtube_description,
self._get_utm_values())
video_endpoint_url = url_join(self.env['social.media']._YOUTUBE_ENDPOINT, "youtube/v3/videos")
result = requests.put(video_endpoint_url,
params={
'access_token': self.account_id.youtube_access_token,
'part': 'snippet,status',
},
json={
'id': self.youtube_video_id,
'snippet': {
'title': self.post_id.youtube_title,
'description': youtube_description,
# for some reason the category ID is required, even if we never change it
'categoryId': self.post_id.youtube_video_category_id,
},
'status': {
'privacyStatus': self.post_id.youtube_video_privacy,
'embeddable': True
}
},
timeout=5
)
if (result.ok):
values = {
'state': 'posted',
'failure_reason': False
}
else:
result_json = result.json()
error_message = _('An error occurred.')
youtube_error = result_json.get('error')
if youtube_error:
error_reason = youtube_error.get('errors', [{}])[0].get('reason')
if youtube_error.get('code') == 404 and error_reason == 'videoNotFound':
error_message = _('The video you are trying to publish has been deleted from YouTube.')
elif youtube_error.get('status') == 'INVALID_ARGUMENT':
error_message = _('Your video is missing a correct title or description.')
else:
error_message = youtube_error.get('errors', [{}])[0].get('message') or error_reason
values = {
'state': 'failed',
'failure_reason': error_message
}
self.write(values)