Shoko.Server/API/v3/Controllers/FileController.cs
/// <summary>
/// Link multiple files to one or more episodes in a series.
/// </summary>
/// <param name="body">The body.</param>
/// <returns></returns>
Link multiple files to one or more episodes in a series.
Link multiple files to one or more episodes in a series .
[HttpPost("LinkFromSeries")]
        public ActionResult LinkMultipleFiles([FromBody] File.Input.LinkSeriesMultipleBody body)
        {
            if (body.fileIDs.Length == 0)
                return BadRequest("`fileIDs` must contain at least one element.");
            var files = new List<SVR_VideoLocal>(body.fileIDs.Length);
            for (int index = 0, fileID = body.fileIDs[0]; index < body.fileIDs.Length; fileID = body.fileIDs[++index]) {
                var file = RepoFactory.VideoLocal.GetByID(fileID);
                if (file == null)
                    return BadRequest($"Unable to find file entry for `fileIDs[{index}]`.");
                files[index] = file;
            }
            var series = RepoFactory.AnimeSeries.GetByID(body.seriesID);
            if (series == null) return BadRequest("Unable to find series entry");
            var episodeType = EpisodeType.Episode;
            var (rangeStart, startType, startErrorMessage) = Helpers.ModelHelper.GetEpisodeNumberAndTypeFromInput(body.rangeStart);
            if (!string.IsNullOrEmpty(startErrorMessage)) {
                return BadRequest(string.Format(startErrorMessage, "rangeStart"));
            }
            if (startType.HasValue) episodeType = startType.Value;
            var rangeEnd = rangeStart + files.Count - 1;
            var totalEpisodes = Helpers.ModelHelper.GetTotalEpisodesForType(series.GetAnimeEpisodes(), episodeType);
            if (rangeStart < 1) {
                return BadRequest("`rangeStart` cannot be lower than 1");
            }
            if (rangeStart > totalEpisodes) {
                return BadRequest("`rangeStart` cannot be higher than the total number of episodes for the selected type.");
            }
            if (rangeEnd < rangeStart) {
                return BadRequest("`rangeEnd`cannot be lower than `rangeStart`.");
            }
            if (rangeEnd > totalEpisodes) {
                return BadRequest("`rangeEnd` cannot be higher than the total number of episodes for the selected type.");
            }
            var fileCount = 1;
            var singleEpisode = body.singleEpisode;
            var episodeNumber = rangeStart;
            foreach (var file in files) {
                var anidbEpisode = RepoFactory.AniDB_Episode.GetByAnimeIDAndEpisodeTypeNumber(series.AniDB_ID, episodeType, episodeNumber)[0];
                if (anidbEpisode == null)
                    return InternalError("Could not find the AniDB entry for episode");
                var episode = RepoFactory.AnimeEpisode.GetByAniDBEpisodeID(anidbEpisode.EpisodeID);
                if (episode == null)
                    return InternalError("Could not find episode entry");
                var command = new CommandRequest_LinkFileManually(file.VideoLocalID, episode.AnimeEpisodeID);
                if (singleEpisode) 
                    command.Percentage = (int) Math.Round((double) (fileCount / files.Count * 100));
                else
                    episodeNumber++;
                if (RemoveXRefsForFile(file))
                    return BadRequest($"Cannot remove associations created from AniDB data for file '{file.VideoLocalID}'");
                fileCount++;
                command.Save();
            }
            return Ok();
        }
[ HttpPost ( " " ) ] public ActionResult LinkMultipleFiles ( [ FromBody ] File . Input . LinkSeriesMultipleBody body ) { if ( body . fileIDs . Length == 0 ) return BadRequest ( " " ) ; var files = new List < SVR_VideoLocal > ( body . fileIDs . Length ) ; for ( int index = 0 , fileID = body . fileIDs [ 0 ] ; index < body . fileIDs . Length ; fileID = body . fileIDs [ ++ index ] ) var file = RepoFactory . VideoLocal . GetByID ( fileID ) ; if ( file == null ) return BadRequest ( $" Unable to find file entry for `fileIDs[ { index } ]`. " ) ; files [ index ] = file ; } var series = RepoFactory . AnimeSeries . GetByID ( body . seriesID ) ; if ( series == null ) return BadRequest ( " " ) ; var episodeType = EpisodeType . Episode ; var ( rangeStart , startType , startErrorMessage ) = Helpers . ModelHelper . GetEpisodeNumberAndTypeFromInput ( body . rangeStart ) ; if ( ! string . IsNullOrEmpty ( startErrorMessage ) ) { return BadRequest ( string . Format ( startErrorMessage , " " ) ) ; } if ( startType . HasValue ) episodeType = startType . Value ; var rangeEnd = rangeStart + files . Count - 1 ; var totalEpisodes = Helpers . ModelHelper . GetTotalEpisodesForType ( series . GetAnimeEpisodes ( ) , episodeType ) ; if ( rangeStart < 1 ) { return BadRequest ( " " ) ; } if ( rangeStart > totalEpisodes ) { return BadRequest ( " " ) ; } if ( rangeEnd < rangeStart ) { return BadRequest ( " " ) ; } if ( rangeEnd > totalEpisodes ) { return BadRequest ( " " ) ; } var fileCount = 1 ; var singleEpisode = body . singleEpisode ; var episodeNumber = rangeStart ; foreach ( var file in files ) { var anidbEpisode = RepoFactory . AniDB_Episode . GetByAnimeIDAndEpisodeTypeNumber ( series . AniDB_ID , episodeType , episodeNumber ) [ 0 ] ; if ( anidbEpisode == null ) return InternalError ( " " ) ; var episode = RepoFactory . AnimeEpisode . GetByAniDBEpisodeID ( anidbEpisode . EpisodeID ) ; if ( episode == null ) return InternalError ( " " ) ; var command = new CommandRequest_LinkFileManually ( file . VideoLocalID , episode . AnimeEpisodeID ) ; if ( singleEpisode ) command . Percentage = ( int ) Math . Round ( ( double ) ( fileCount / files . Count * 100 ) ) ; else episodeNumber ++ ; if ( RemoveXRefsForFile ( file ) ) return BadRequest ( $" Cannot remove associations created from AniDB data for file ' { file . VideoLocalID } ' " ) ; fileCount ++ ; command . Save ( ) ; } return Ok ( ) ; }
Link multiple files to one or more episodes in a series.
Link multiple files to one or more episodes in a series .
// Validate all the file ids. // Set the episode type if it was included in the input. // Validate the range.
None
File.Input.LinkSeriesMultipleBody
[FromBody]
body
None