Example #1
0
        private async Task <IAttemptResult> EncodeVideosAsync(IWatchSession session, IDownloadContext context, IDownloadSettings settings, Action <string> onMessage, IEnumerable <string> segmentFilePaths, CancellationToken token)
        {
            var encodeSetting = new EncodeSettings()
            {
                FilePath           = context.FileName,
                CommandFormat      = settings.CommandFormat,
                TsFilePaths        = segmentFilePaths,
                IsOverwriteEnable  = settings.Overwrite,
                IsOverrideDTEnable = settings.OverrideVideoFileDateToUploadedDT,
                UploadedOn         = session.Video !.DmcInfo.UploadedOn,
                IsNoEncodeEnable   = settings.SaveWithoutEncode,
            };

            try
            {
                await this._encorder.EncodeAsync(encodeSetting, onMessage, token);
            }
            catch (Exception e)
            {
                this._logger.Error($"ファイルの変換中にエラーが発生しました。({this.context!.GetLogContent()})", e);
                onMessage("動画の変換中にエラー発生");
                return(AttemptResult.Fail($"ファイルの変換中にエラーが発生しました。(詳細: {e.Message})"));
            }

            return(AttemptResult.Succeeded());
        }
Example #2
0
        private string GetFileName(IWatchSession session, IDownloadSettings settings)
        {
            string?economySuffix = session.Video !.DmcInfo.IsEnonomy ? settings.EconomySuffix : null;
            string?suffix        = economySuffix;
            string ext           = settings.SaveWithoutEncode ? FileFolder.TsFileExt : FileFolder.Mp4FileExt;
            string format        = string.IsNullOrEmpty(settings.FileNameFormat) ? Format.DefaultFileNameFormat : settings.FileNameFormat;

            return(this._pathOrganizer.GetFilePath(format, session.Video !.DmcInfo, ext, settings.FolderPath, settings.IsReplaceStrictedEnable, settings.Overwrite, suffix));
        }
Example #3
0
        private async Task <IAttemptResult <IStreamInfo> > GetStream(IWatchSession session, uint resolution)
        {
            IStreamInfo targetStream;

            try
            {
                IStreamsCollection streams = await session.GetAvailableStreamsAsync();

                targetStream = streams.GetStream(resolution);
            }
            catch (Exception e)
            {
                this._logger.Error($"ストリームの取得に失敗しました。({this.context!.GetLogContent()})", e);
                return(AttemptResult <IStreamInfo> .Fail("ストリームの取得に失敗しました。", e));
            }

            return(AttemptResult <IStreamInfo> .Succeeded(targetStream));
        }
Example #4
0
        private async Task <IAttemptResult> EnsureSessionAsync(IWatchSession session, IDownloadSettings settings)
        {
            await session.EnsureSessionAsync(settings.NiconicoId);

            if (!session.IsSessionEnsured)
            {
                string message = session.State switch
                {
                    WatchSessionState.HttpRequestOrPageAnalyzingFailure => "視聴ページの取得、または解析に失敗しました。",
                    WatchSessionState.EncryptedVideo => "暗号化された動画のため、ダウンロードできません。",
                    WatchSessionState.SessionEnsuringFailure => "セッションの確立に失敗しました。",
                    _ => "不明なエラーにより、セッションの確立に失敗しました。"
                };

                return(AttemptResult.Fail(message));
            }
            else
            {
                this._logger.Log($"視聴セッションを確立しました。({this.context!.GetLogContent()})");
                return(AttemptResult.Succeeded());
            }
        }
Example #5
0
        /// <summary>
        /// 動画情報ファイルを保存する
        /// </summary>
        /// <param name="setting"></param>
        /// <param name="dmcInfo"></param>
        /// <returns></returns>
        public IAttemptResult DownloadVideoInfoAsync(IDownloadSettings setting, IWatchSession session, Action <string> onMessage)
        {
            if (session.Video is null)
            {
                return(AttemptResult.Fail("動画情報が未取得です。"));
            }

            onMessage($"動画情報の保存を開始します。");
            this._logger.Log($"{session.Video.Id}の動画情報保存を開始");

            string fileName = this._pathOrganizer.GetFilePath(setting.FileNameFormat, session.Video.DmcInfo, setting.VideoInfoExt, setting.FolderPath, setting.IsReplaceStrictedEnable, setting.Overwrite, setting.VideoInfoSuffix);


            var filePath = Path.Combine(setting.FolderPath, fileName);

            string content = setting.VideoInfoType switch
            {
                VideoInfoTypeSettings.Json => this._producer.GetJsonContent(session.Video.DmcInfo),
                VideoInfoTypeSettings.Xml => this._producer.GetXmlContent(session.Video.DmcInfo),
                _ => this._producer.GetContent(session.Video.DmcInfo),
            };

            try
            {
                IOUtils.CreateDirectoryIfNotExist(fileName);
                this._fileIO.Write(filePath, content);
            }
            catch (Exception e)
            {
                onMessage("動画情報ファイルの書き込みに失敗しました。");
                this._logger.Error("動画情報ファイルの書き込みに失敗しました。", e);
                return(AttemptResult.Fail($"動画情報ファイルの書き込みに失敗しました。(詳細:{e.Message})"));
            }

            onMessage($"動画情報ファイルを保存しました。");
            return(AttemptResult.Succeeded());
        }
        public async Task <IAttemptResult> DownloadIchibaInfo(IWatchSession session, IDownloadSettings settings, Action <string> onMessage, IDownloadContext context)
        {
            if (session.Video is null)
            {
                return(new AttemptResult()
                {
                    Message = "セッション情報のVideoがnullです。"
                });
            }

            onMessage($"市場APIへのアクセスを開始します。({session.Video.Id})");
            var getResult = await this._niconicoIchibaHandler.GetIchibaInfo(session.Video.Id);

            if (!getResult.IsSucceeded || getResult.Data is null)
            {
                onMessage($"市場APIからの情報取得に失敗しました。({session.Video.Id})");
                if (getResult.Exception is not null)
                {
                    this._logger.Error($"市場情報の取得に失敗しました。(詳細:{getResult.Message} ,{context.GetLogContent()})", getResult.Exception);
                }
                else
                {
                    this._logger.Error($"市場情報の取得に失敗しました。(詳細:{getResult.Message} ,{context.GetLogContent()})");
                }
                return(new AttemptResult()
                {
                    Message = getResult.Message
                });
            }

            onMessage($"市場APIからの情報取得を取得しました。({session.Video.Id})");

            string content;

            if (settings.IchibaInfoType != IchibaInfoTypeSettings.Html)
            {
                try
                {
                    content = this.GetContent(getResult.Data, settings.IchibaInfoType == IchibaInfoTypeSettings.Xml);
                }
                catch (Exception e)
                {
                    this._logger.Error($"市場情報のシリアル化に失敗しました。(詳細:{getResult.Message} ,{context.GetLogContent()})", e);
                    onMessage($"市場情報のシリアル化に失敗しました。({session.Video.Id})");
                    return(new AttemptResult()
                    {
                        Message = "市場情報のシリアル化に失敗しました。"
                    });
                }
            }
            else
            {
                try
                {
                    content = this.GetHtmlContent(getResult.Data, session.Video.Id);
                }
                catch (Exception e)
                {
                    this._logger.Error($"市場情報のシリアル化に失敗しました。(詳細:{getResult.Message} ,{context.GetLogContent()})", e);
                    onMessage($"市場情報のシリアル化に失敗しました。({session.Video.Id})");
                    return(new AttemptResult()
                    {
                        Message = "市場情報のシリアル化に失敗しました。"
                    });
                }
            }


            string filePath = this._path.GetFilePath(settings.FileNameFormat, session.Video !.DmcInfo, settings.IchibaInfoExt, settings.FolderPath, settings.IsReplaceStrictedEnable, settings.Overwrite, settings.IchibaInfoSuffix);

            try
            {
                this._fileIO.Write(filePath, content);
            }
            catch (Exception e)
            {
                this._logger.Error($"市場情報ファイルの書き込みに失敗しました。({context.GetLogContent()})", e);
                onMessage($"市場情報ファイルの書き込みに失敗しました。({session.Video.Id})");
                return(new AttemptResult()
                {
                    Message = $"市場情報ファイルの書き込みに失敗しました。(詳細:{e.Message})"
                });
            }

            onMessage($"市場情報ファイルの保存が完了しました。({session.Video.Id})");
            return(new AttemptResult()
            {
                IsSucceeded = true
            });
        }
        /// <summary>
        /// 市場情報をダウンロードする
        /// </summary>
        private async Task <IAttemptResult> DownloadIchibaInfoAsync(IDownloadSettings settings, IWatchSession session, Action <string> onMessage, IDownloadContext context)
        {
            var            iDownloader = DIFactory.Provider.GetRequiredService <IIchibaInfoDownloader>();
            IAttemptResult result;

            try
            {
                result = await iDownloader.DownloadIchibaInfo(session, settings, onMessage, context);
            }
            catch (Exception e)
            {
                this.logger.Error("市場情報のダウンロードに失敗しました。", e);
                return(AttemptResult.Fail($"市場情報のダウンロードに失敗しました。({e.Message})"));
            }
            return(result);
        }
        /// <summary>
        /// コメントをダウンロードする
        /// </summary>
        private async Task <IAttemptResult> TryDownloadCommentAsync(IDownloadSettings settings, IWatchSession session, Action <string> onMessage, IDownloadContext context, CancellationToken token)
        {
            Cdl::ICommentDownloader?      v1 = null;
            V2Comment::ICommentDownloader?v2 = null;

            if (settings.EnableExperimentalCommentSafetySystem)
            {
                v2 = DIFactory.Provider.GetRequiredService <V2Comment::ICommentDownloader>();
            }
            else
            {
                v1 = DIFactory.Provider.GetRequiredService <Cdl::ICommentDownloader>();
            }

            IAttemptResult result;

            try
            {
                result = v2 is null ? await v1 !.DownloadComment(session, settings, onMessage, context, token) : await v2.DownloadCommentAsync(session.Video !.DmcInfo, settings, context, token);
            }
            catch (Exception e)
            {
                this.logger.Error("コメントのダウンロードに失敗しました。", e);
                return(AttemptResult.Fail($"コメントのダウンロードに失敗しました。({e.Message})"));
            }

            return(result);
        }
        /// <summary>
        /// サムネイルをダウンロードする
        /// </summary>
        private async Task <IAttemptResult> TryDownloadThumbAsync(IDownloadSettings setting, IWatchSession session)
        {
            var            thumbDownloader = DIFactory.Provider.GetRequiredService <Tdl::IThumbDownloader>();
            IAttemptResult result;

            try
            {
                result = await thumbDownloader.DownloadThumbnailAsync(setting, session);
            }
            catch (Exception e)
            {
                this.logger.Error($"サムネイルのダウンロードに失敗しました。", e);
                return(AttemptResult.Fail($"サムネイルのダウンロードに失敗しました。(詳細:{e.Message})"));
            }

            return(result);
        }
        /// <summary>
        /// 動画情報をダウンロードする
        /// </summary>
        private IAttemptResult TryDownloadDescriptionAsync(IDownloadSettings settings, IWatchSession session, Action <string> onMessage)
        {
            var descriptionDownloader = DIFactory.Provider.GetRequiredService <DDL::IDescriptionDownloader>();

            IAttemptResult result;

            try
            {
                result = descriptionDownloader.DownloadVideoInfoAsync(settings, session, onMessage);
            }
            catch (Exception e)
            {
                this.logger.Error($"動画情報のダウンロードに失敗しました。", e);
                return(AttemptResult.Fail($"動画情報のダウンロードに失敗しました。(詳細:{e.Message})"));
            }

            return(result);
        }
        /// <summary>
        /// 非同期で動画をダウンロードする
        /// </summary>
        private async Task <IAttemptResult> TryDownloadVideoAsync(IDownloadSettings settings, Action <string> onMessage, IWatchSession session, IDownloadContext context, CancellationToken token)
        {
            var            videoDownloader = DIFactory.Provider.GetRequiredService <Vdl::IVideoDownloader>();
            IAttemptResult result;

            try
            {
                result = await videoDownloader.DownloadVideoAsync(settings, onMessage, context, session, token);
            }
            catch (Exception e)
            {
                this.logger.Error($"動画のダウンロードに失敗しました。({context.GetLogContent()})", e);
                return(AttemptResult.Fail($"動画のダウンロードに失敗しました。(詳細:{e.Message})"));
            }
            return(result);
        }
Example #12
0
        public async Task <IAttemptResult> DownloadComment(IWatchSession session, IDownloadSettings settings, Action <string> onMessage, IDownloadContext context, CancellationToken token)
        {
            if (session.Video is null)
            {
                return(AttemptResult.Fail("動画情報が未取得です。"));
            }

            string filePath      = this._pathOrganizer.GetFilePath(settings.FileNameFormat, session.Video !.DmcInfo, ".xml", settings.FolderPath, settings.IsReplaceStrictedEnable, settings.Overwrite);
            string ownerFileName = this._pathOrganizer.GetFilePath(settings.FileNameFormat, session.Video !.DmcInfo, ".xml", settings.FolderPath, settings.IsReplaceStrictedEnable, settings.Overwrite, settings.OwnerComSuffix);

            if (token.IsCancellationRequested)
            {
                return(this.GetCancelledResult());
            }

            onMessage("コメントのダウンロードを開始します。");
            this._logger.Log($"{settings.NiconicoId}のコメントダウンロードを開始します。({context.GetLogContent()})");

            ICommentCollection result;

            try
            {
                result = await this._client.DownloadCommentAsync(session.Video !.DmcInfo, settings, onMessage, context, token);
            }
            catch (Exception e)
            {
                this._logger.Error($"コメントの取得に失敗しました。({context.GetLogContent()})", e);
                return(AttemptResult.Fail($"コメントの取得に失敗しました。(詳細:{e.Message})"));
            }
            onMessage("コメントのダウンロードが完了しました。");

            if (token.IsCancellationRequested)
            {
                return(this.GetCancelledResult());
            }

            onMessage("コメントの変換処理を開始します。");
            IStoreCommentsData data;

            try
            {
                data = this._commentConverter.ConvertToStoreCommentsData(result, settings);
            }
            catch (Exception e)
            {
                this._logger.Error($"コメントの解析に失敗しました。({context.GetLogContent()})", e);
                return(AttemptResult.Fail($"コメントの解析に失敗しました。"));
            }
            onMessage("コメントの変換処理が完了しました。");

            data.FilePath     = filePath;
            data.OwnerFilPath = ownerFileName;

            if (token.IsCancellationRequested)
            {
                return(this.GetCancelledResult());
            }

            onMessage($"コメントの書き込みを開始します。");
            try
            {
                this._commentStream.Write(data, settings.Overwrite);
            }
            catch (Exception e)
            {
                this._logger.Error($"コメントの書き込みに失敗しました。({context.GetLogContent()})", e);
                return(AttemptResult.Fail("コメントの書き込みに失敗しました。"));
            }
            onMessage("コメントのダウンロードが完了しました。");
            this._logger.Log($"コメントのダウンロードが完了しました。({context.GetLogContent()})");

            return(AttemptResult.Succeeded());
        }
Example #13
0
        public async Task <IAttemptResult> DownloadVideoAsync(IDownloadSettings settings, Action <string> onMessage, IDownloadContext context, IWatchSession session, CancellationToken token)
        {
            IAttemptResult OnCanceled()
            {
                this._logger.Log($"ユーザーの操作によって動画のダウンロード処理がキャンセルされました。({context.GetLogContent()})");
                onMessage("ダウンロードをキャンセル");
                return(AttemptResult.Fail("処理がキャンセルされました"));
            }

            this.context = context;
            this._logger.Log($"動画のダウンロードを開始しました。({context.GetLogContent()})");

            if (session.IsSessionExipired)
            {
                this._logger.Log($"セッションが失効していたため動画のダウンロードをキャンセルします。({context.GetLogContent()})");
                return(AttemptResult <string> .Fail("セッションが失効済のためダウンロード出来ません。"));
            }

            if (!session.IsSessionEnsured)
            {
                if (token.IsCancellationRequested)
                {
                    return(OnCanceled());
                }

                IAttemptResult sessionR = await this.EnsureSessionAsync(session, settings);

                if (!sessionR.IsSucceeded)
                {
                    onMessage(sessionR.Message ?? "");
                    return(sessionR);
                }
            }


            //ファイル名取得
            string fileName = this.GetFileName(session, settings);

            context.FileName = fileName;


            if (token.IsCancellationRequested)
            {
                return(OnCanceled());
            }


            //ストリーム系
            IAttemptResult <IStreamInfo> streamResult = await this.GetStream(session, settings.VerticalResolution);

            if (!streamResult.IsSucceeded || streamResult.Data is null)
            {
                return(AttemptResult.Fail(streamResult.Message, streamResult.Exception));
            }

            IStreamInfo   targetStream        = streamResult.Data;
            List <string> rawsegmentFilePaths = targetStream.StreamUrls.Select(u => u.FileName).ToList();

            context.ActualVerticalResolution = targetStream.Resolution?.Vertical ?? 0;
            context.OriginalSegmentsCount    = targetStream.StreamUrls.Count;


            if (token.IsCancellationRequested)
            {
                return(OnCanceled());
            }


            //レジューム系
            string segmentDirectoryName;
            IAttemptResult <string> sResult = settings.ResumeEnable ? this.GetAndSetSegmentsDirectoryInfoIfExists(settings.NiconicoId, targetStream.Resolution?.Vertical ?? 0, targetStream) : AttemptResult <string> .Fail();

            if (sResult.IsSucceeded && sResult.Data is not null)
            {
                segmentDirectoryName = sResult.Data;
                onMessage("DLをレジューム");
                this._logger.Log($"ダウンロードをレジュームします。({context.GetLogContent()})");
            }
            else
            {
                segmentDirectoryName = $"{settings.NiconicoId}-{targetStream.Resolution?.Vertical ?? 0}-{DateTime.Now.ToString("yyyy-MM-dd")}";
            }
            List <string> segmentFilePaths = rawsegmentFilePaths.Select(p => Path.Combine(AppContext.BaseDirectory, "tmp", segmentDirectoryName, p)).ToList();


            //DL系
            IAttemptResult downloadresult = await this.DownloadVideoInternalAsync(targetStream, onMessage, context, settings.MaxParallelSegmentDLCount, segmentDirectoryName, token);

            if (!downloadresult.IsSucceeded)
            {
                return(downloadresult);
            }

            if (token.IsCancellationRequested)
            {
                return(OnCanceled());
            }

            onMessage("動画を変換中...");
            IAttemptResult encodeResult = await this.EncodeVideosAsync(session, context, settings, onMessage, segmentFilePaths, token);

            if (!encodeResult.IsSucceeded)
            {
                return(encodeResult);
            }
            onMessage("動画の変換が完了");

            this.DeleteTmpFolder(segmentDirectoryName, onMessage);


            bool isEconomy = session.Video !.DmcInfo.IsEnonomy;

            if (settings.IsEconomy && settings.DeleteExistingEconomyFile && !isEconomy)
            {
                this.RemoveEconomyFile(settings.FilePath);
            }

            this._fileStorehandler.Add(settings.NiconicoId, Path.Combine(settings.FolderPath, fileName));

            this._logger.Log($"動画のダウンロードが完了しました。({context.GetLogContent()})");

            return(AttemptResult.Succeeded());
        }
Example #14
0
        public async Task <IAttemptResult> DownloadThumbnailAsync(IDownloadSettings settings, IWatchSession session)
        {
            if (session.Video is null)
            {
                return(AttemptResult.Fail("動画情報が未取得です。"));
            }

            var filepath = this._pathOrganizer.GetFilePath(settings.FileNameFormat, session.Video !.DmcInfo, settings.ThumbnailExt, settings.FolderPath, settings.IsReplaceStrictedEnable, settings.Overwrite, settings.ThumbSuffix);

            string?thumbUrl;

            try
            {
                thumbUrl = session.Video !.DmcInfo.ThumbInfo.GetSpecifiedThumbnail(settings.ThumbSize);
            }
            catch (Exception e)
            {
                this._logger.Error($"サムネイルURLの取得に失敗しました。", e);
                return(AttemptResult.Fail("サムネイルのURLを取得できませんでした。"));
            }


            byte[] data;
            try
            {
                data = await this.DownloadAsync(thumbUrl);
            }
            catch (Exception e)
            {
                this._logger.Error($"サムネイルの取得に失敗しました。", e);
                return(AttemptResult.Fail($"サムネイルの取得に失敗しました。(詳細: {e.Message})"));
            }

            try
            {
                this.WriteThumb(data, filepath);
            }
            catch (Exception e)
            {
                this._logger.Error($"サムネイルの保存に失敗しました。", e);
                return(AttemptResult.Fail($"サムネイルの保存に失敗しました。(詳細: {e.Message})"));
            }

            return(AttemptResult.Succeeded());
        }