using Dapper; using Dapper.Contrib.Extensions; using Newtonsoft.Json; using NPOI.XSSF.UserModel; using Org.BouncyCastle.Asn1.Ocsp; using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Text; using System.Web; using static DbTableClass; using Org.BouncyCastle.Crypto.Operators; using System.Globalization; public class youtubeUpdateClass : IHostedService, IDisposable { static Timer _timer; private int execCount = 0; DbConn dbConn = new DbConn(); SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString")); public youtubeUpdateClass() { } public Task StartAsync(CancellationToken cancellationToken) { _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(15 * 60)); return Task.CompletedTask; } public async void DoWork(object state) { conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWork')"); //利用 Interlocked 計數防止重複執行 Interlocked.Increment(ref execCount); if (execCount == 1) { conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWork,execCount == 1時執行更新工作')"); //撈出Youtube頻道清單 List kolMedias = conn.Query("select * from kolMedia where option_uid = 'media' and optionItem_uid = 'media003' ").ToList(); foreach(kolMedia mediaItem in kolMedias) { string overDate = DateTime.Now.AddDays(int.Parse(GlobalClass.appsettings("UpdateByDay")) * -1).ToString("yyyy/MM/dd HH:mm:ss"); updateLog objLog = conn.QueryFirstOrDefault("select * from updateLog where updateLog_type = 'YouTube' and updateLog_result = 'success' and updateLog_kol_uid = @kol_uid and updateLog_kolMedia_uid = @kolMedia_uid and updateLog_updateTime >= @overDate ", new { kol_uid = mediaItem.kol_uid, kolMedia_uid = mediaItem.kolMedia_uid, overDate = overDate }); if (objLog == null) { //撈取youtube帳號訂閱數 string youtubeChannelsApi = "https://www.googleapis.com/youtube/v3/channels?part=statistics,snippet,contentDetails&forHandle=" + mediaItem.kolMedia_accountName + "&key=" + GlobalClass.appsettings("GoogleKey"); string channelsStatus = ""; string channel_id = ""; using (var httpClient = new HttpClient()) { using (var response = await httpClient.GetAsync(youtubeChannelsApi)) { channelsStatus = await response.Content.ReadAsStringAsync(); } } dynamic channelsObj; channelsObj = JsonConvert.DeserializeObject(channelsStatus); if (channelsObj.items != null) { channel_id = channelsObj.items[0].id; string subscriberCount = channelsObj.items[0].statistics.subscriberCount; mediaItem.kolMedia_fansNum = (int)channelsObj.items[0].statistics.subscriberCount; string youtube_uid = GlobalClass.CreateRandomCode(32); youtube newYoutube = new youtube(); newYoutube.youtube_uid = youtube_uid; newYoutube.kol_uid = mediaItem.kol_uid; newYoutube.kolMedia_uid = mediaItem.kolMedia_uid; newYoutube.youtube_account = mediaItem.kolMedia_accountName; newYoutube.youtube_name = channelsObj.items[0].snippet.title; newYoutube.youtube_photo = channelsObj.items[0].snippet.thumbnails.high.url; newYoutube.youtube_revoke = "N"; newYoutube.youtube_subscriberCount = (int)channelsObj.items[0].statistics.subscriberCount; newYoutube.youtube_viewCount = (int)channelsObj.items[0].statistics.viewCount; newYoutube.youtube_json = channelsStatus; //取得上傳影片的playlist id string playlist_id = channelsObj.items[0].contentDetails.relatedPlaylists.uploads; string youtubePlaylistApi = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=5&key=" + GlobalClass.appsettings("GoogleKey") + "&playlistId=" + playlist_id; string youtubePlaylistJson = ""; using (var httpClient = new HttpClient()) { using (var response = await httpClient.GetAsync(youtubePlaylistApi)) { youtubePlaylistJson = await response.Content.ReadAsStringAsync(); } } dynamic youtubePlaylistObj; youtubePlaylistObj = JsonConvert.DeserializeObject(youtubePlaylistJson); string videoIdList = ""; foreach (var item in youtubePlaylistObj.items) { videoIdList += item.snippet.resourceId.videoId + ","; } videoIdList = videoIdList.TrimEnd(','); if (videoIdList == "") { updateLog failedLog = new updateLog(); failedLog.updateLog_text = "此Youtube帳號 " + mediaItem.kolMedia_accountName + "(" + mediaItem.kolMedia_displayName + ") Google Youtube Data Api 的Video數量 回傳0個!"; failedLog.updateLog_kolMedia_uid = mediaItem.kolMedia_uid; failedLog.updateLog_kolMedia_accountName = mediaItem.kolMedia_accountName; failedLog.updateLog_kolMedia_displayName = mediaItem.kolMedia_displayName; failedLog.updateLog_kol_uid = mediaItem.kol_uid; failedLog.updateLog_type = "YouTube"; failedLog.updateLog_result = "failed"; conn.Insert(failedLog); } else { string youtubeVideoApi = "https://www.googleapis.com/youtube/v3/videos?part=statistics,snippet&key=" + GlobalClass.appsettings("GoogleKey") + "&id=" + videoIdList; string youtubeVideoJson = ""; using (var httpClient = new HttpClient()) { using (var response = await httpClient.GetAsync(youtubeVideoApi)) { youtubeVideoJson = await response.Content.ReadAsStringAsync(); } } dynamic youtubeVideoObj; youtubeVideoObj = JsonConvert.DeserializeObject(youtubeVideoJson); int totalViewNum = 0; int videosNum = 0; List youtubeDetailList = new List(); foreach (var item in youtubeVideoObj.items) { totalViewNum += (int)item.statistics.viewCount; videosNum++; youtubeDetail objDetail = new youtubeDetail(); objDetail.youtube_uid = youtube_uid; objDetail.youtubeDetail_uid = "ytd_" + GlobalClass.CreateRandomCode(16); objDetail.youtubeDetail_title = item.snippet.title; objDetail.youtubeDetail_description = item.snippet.description; string publishedAt = item.snippet.publishedAt; var published = DateTime.Parse(publishedAt, null, DateTimeStyles.None); objDetail.youtubeDetail_publishedAt = published; objDetail.youtubeDetail_commentCount = (int)item.statistics.commentCount; objDetail.youtubeDetail_viewCount = (int)item.statistics.viewCount; objDetail.youtubeDetail_likeCount = (int)item.statistics.likeCount; objDetail.youtubeDetail_favoriteCount = (int)item.statistics.favoriteCount; objDetail.youtubeDetail_thumbnails = item.snippet.thumbnails.maxres.url; objDetail.youtubeDetail_videoId = item.id; objDetail.youtubeDetail_json = JsonConvert.SerializeObject(item); youtubeDetailList.Add(objDetail); } double avg = ((totalViewNum / videosNum) + 0.5); newYoutube.youtube_avgViewCount = (int)System.Math.Floor(avg); conn.Execute("update youtube set youtube_revoke = 'Y' where kol_uid = @kol_uid and kolMedia_uid = @kolMedia_uid", new { kol_uid = mediaItem.kol_uid, kolMedia_uid = mediaItem.kolMedia_uid }); conn.Insert(youtubeDetailList); conn.Insert(newYoutube); } updateLog successLog = new updateLog(); successLog.updateLog_text = "此Youtube帳號 " + mediaItem.kolMedia_accountName + "(" + mediaItem.kolMedia_displayName + ") Youtube資料更新成功"; successLog.updateLog_kolMedia_uid = mediaItem.kolMedia_uid; successLog.updateLog_kolMedia_accountName = mediaItem.kolMedia_accountName; successLog.updateLog_kolMedia_displayName = mediaItem.kolMedia_displayName; successLog.updateLog_kol_uid = mediaItem.kol_uid; successLog.updateLog_type = "YouTube"; successLog.updateLog_result = "success"; successLog.updateLog_uid = channel_id; conn.Insert(successLog); } else { updateLog failedLog = new updateLog(); failedLog.updateLog_text = "此Youtube帳號 " + mediaItem.kolMedia_accountName + "(" + mediaItem.kolMedia_displayName + ") Google Youtube Data Api回傳Null值!"; failedLog.updateLog_kolMedia_uid = mediaItem.kolMedia_uid; failedLog.updateLog_kolMedia_accountName = mediaItem.kolMedia_accountName; failedLog.updateLog_kolMedia_displayName = mediaItem.kolMedia_displayName; failedLog.updateLog_kol_uid = mediaItem.kol_uid; failedLog.updateLog_type = "YouTube"; failedLog.updateLog_result = "failed"; conn.Insert(failedLog); } } } conn.Update(kolMedias); conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWork,執行更新工作結束')"); } Interlocked.Decrement(ref execCount); conn.Execute("insert into schedule (schedule_type, schedule_log) values ('YouTube', '執行DoWork,execCount減1')"); } public Task StopAsync(CancellationToken cancellationToken) { //調整Timer為永不觸發,停用定期排程 _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } }