got seek and end time working on non-direct play Enhance program duration calculation and entry creation in channel services and guide improved guide generation Add debug logging and really agressive program merging logic and placeholder avoidence in XMLTV writer Add a final pass duplicate detection and merging logic in _smartMerge function Refactor XMLTV writing logic: enhance debug logging, streamline program merging, and improve error handling backwards compatibly Human readable time Refactor program configuration modal: move optional position offsets to collapsible advanced options section Update program configuration modal: rename position offset labels to custom start and end time Changed how I build the guide based on an implementation that's closer to the original implementation and requires less changes. Reverted Unneeded Changes Simplified how StreamSeeK and custom end positions are applied in both transcoding and direct play. Implement merging of adjacent programs with the same ratingKey in TVGuideService Made merging-adjacent programs optional and disabled by default custom time can actuall be set cleanup Enhance time input validation for program duration and seek positions
188 lines
13 KiB
HTML
188 lines
13 KiB
HTML
<div ng-show="program">
|
|
<div class="modal" tabindex="-1" role="dialog" style="display: block; background-color: rgba(0, 0, 0, .5);">
|
|
<div class="modal-dialog modal-dialog-scrollable modal-xl" role="document">
|
|
<div class="modal-content">
|
|
<div>
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Program Config (EPG)</h5>
|
|
</div>
|
|
</div>
|
|
<div class="modal-body container">
|
|
<select ng-model="program.type" class="pull-right">
|
|
<option>movie</option>
|
|
<option>episode</option>
|
|
<option>track</option>
|
|
</select>
|
|
<div ng-if="program.type === 'track'">
|
|
<label>Track Title
|
|
<span class="text-danger pull-right">{{error.title}}</span>
|
|
</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.title"></input>
|
|
<label>Subtitle</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.subtitle"></input>
|
|
<label>Summary</label>
|
|
<textarea class="form-control form-control-sm" ng-model="program.summary"></textarea>
|
|
<label>Rating</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.rating"></input>
|
|
<label>Icon</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.icon"></input>
|
|
<h6>Icon Preview</h6>
|
|
<div class="text-center">
|
|
<img class="img" ng-src="{{program.icon}}" style="max-width: 200px;"></img>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header" ng-click="trackAdvancedOpen = !trackAdvancedOpen" style="cursor: pointer;">
|
|
<h6 class="mb-0">Advanced Options <i class="float-right" ng-class="{'fa fa-chevron-down': !trackAdvancedOpen, 'fa fa-chevron-up': trackAdvancedOpen}"></i></h6>
|
|
</div>
|
|
<div class="collapse" ng-class="{'show': trackAdvancedOpen}">
|
|
<div class="card-body">
|
|
<label>Custom Start Time (optional)</label>
|
|
<div class="form-row mb-3">
|
|
<div class="col">
|
|
<input class="form-control form-control-sm" type="text" ng-model="timeInput.seek" placeholder="MM:SS (leave blank for start)">
|
|
<small class="form-text text-muted">Format: minutes:seconds (e.g. 5:30)</small>
|
|
<div ng-show="error && error.seekPosition" class="text-danger">{{error.seekPosition}}</div>
|
|
</div>
|
|
</div>
|
|
<label>Custom End Time (optional)
|
|
<span class="text-danger pull-right">{{error.endPosition}}</span>
|
|
</label>
|
|
<div class="form-row mb-3">
|
|
<div class="col">
|
|
<input class="form-control form-control-sm" type="text" ng-model="timeInput.end" placeholder="MM:SS (leave blank for end)">
|
|
<small class="form-text text-muted">Format: minutes:seconds (e.g. 10:45)</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div ng-if="program.type === 'movie'">
|
|
<label>Movie Title
|
|
<span class="text-danger pull-right">{{error.title}}</span>
|
|
</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.title"></input>
|
|
<label>Subtitle</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.subtitle"></input>
|
|
<label>Summary</label>
|
|
<textarea class="form-control form-control-sm" ng-model="program.summary"></textarea>
|
|
<label>Rating</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.rating"></input>
|
|
<label>Icon</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.icon"></input>
|
|
<h6>Icon Preview</h6>
|
|
<div class="text-center">
|
|
<img class="img" ng-src="{{program.icon}}" style="max-width: 200px;"></img>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header" ng-click="movieAdvancedOpen = !movieAdvancedOpen" style="cursor: pointer;">
|
|
<h6 class="mb-0">Advanced Options <i class="float-right" ng-class="{'fa fa-chevron-down': !movieAdvancedOpen, 'fa fa-chevron-up': movieAdvancedOpen}"></i></h6>
|
|
</div>
|
|
<div class="collapse" ng-class="{'show': movieAdvancedOpen}">
|
|
<div class="card-body">
|
|
<label>Custom Start Time (optional)</label>
|
|
<div class="form-row mb-3">
|
|
<div class="col">
|
|
<input class="form-control form-control-sm" type="text" ng-model="timeInput.seek" placeholder="MM:SS (leave blank for start)">
|
|
<small class="form-text text-muted">Format: minutes:seconds (e.g. 5:30)</small>
|
|
<div ng-show="error && error.seekPosition" class="text-danger">{{error.seekPosition}}</div>
|
|
</div>
|
|
</div>
|
|
<label>Custom End Time (optional)
|
|
<span class="text-danger pull-right">{{error.endPosition}}</span>
|
|
</label>
|
|
<div class="form-row mb-3">
|
|
<div class="col">
|
|
<input class="form-control form-control-sm" type="text" ng-model="timeInput.end" placeholder="MM:SS (leave blank for end)">
|
|
<small class="form-text text-muted">Format: minutes:seconds (e.g. 10:45)</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div ng-if="program.type === 'episode'">
|
|
<label>Show Title
|
|
<span class="text-danger pull-right">{{error.showTitle}}</span>
|
|
</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.showTitle"></input>
|
|
<label>Episode Title
|
|
<span class="text-danger pull-right">{{error.title}}</span>
|
|
</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.title"></input>
|
|
<label>Season
|
|
<span class="text-danger pull-right">{{error.season}}</span>
|
|
</label>
|
|
<input class="form-control form-control-sm" type="number" ng-model="program.season"></input>
|
|
<label>Episode
|
|
<span class="text-danger pull-right">{{error.episode}}</span>
|
|
</label>
|
|
<input class="form-control form-control-sm" type="number" ng-model="program.episode"></input>
|
|
<label>Summary</label>
|
|
<textarea class="form-control form-control-sm" ng-model="program.summary"></textarea>
|
|
<label>Rating</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.rating"></input>
|
|
<label>Icon</label>
|
|
<input class="form-control form-control-sm" type="text" ng-model="program.icon"></input>
|
|
<h6>Icon Preview</h6>
|
|
<div class="row">
|
|
<div class="col-sm-6">
|
|
<div class="text-center">
|
|
<img class="img" ng-src="{{program.icon}}" style="max-width: 200px;"></img>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-6 row" ng-if="program.showIcon">
|
|
<div class="col-sm-6 text-center">
|
|
<label>Show</label>
|
|
<img class="img" ng-src="{{program.showIcon}}" style="max-width: 75px; cursor: pointer;" ng-click="program.icon = program.showIcon"></img>
|
|
</div>
|
|
<div class="col-sm-6 text-center">
|
|
<label>Season</label>
|
|
<img class="img" ng-src="{{program.seasonIcon}}" style="max-width: 75px; cursor: pointer;" ng-click="program.icon = program.seasonIcon"></img>
|
|
</div>
|
|
<div class="col-sm-12 text-center">
|
|
<label>Episode</label>
|
|
<img class="img" ng-src="{{program.episodeIcon}}" style="max-width: 150px; cursor: pointer;" ng-click="program.icon = program.episodeIcon"></img>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header" ng-click="episodeAdvancedOpen = !episodeAdvancedOpen" style="cursor: pointer;">
|
|
<h6 class="mb-0">Advanced Options <i class="float-right" ng-class="{'fa fa-chevron-down': !episodeAdvancedOpen, 'fa fa-chevron-up': episodeAdvancedOpen}"></i></h6>
|
|
</div>
|
|
<div class="collapse" ng-class="{'show': episodeAdvancedOpen}">
|
|
<div class="card-body">
|
|
<label>Custom Start Time (optional)</label>
|
|
<div class="form-row mb-3">
|
|
<div class="col">
|
|
<input class="form-control form-control-sm" type="text" ng-model="timeInput.seek" placeholder="MM:SS (leave blank for start)">
|
|
<small class="form-text text-muted">Format: minutes:seconds (e.g. 5:30)</small>
|
|
<div ng-show="error && error.seekPosition" class="text-danger">{{error.seekPosition}}</div>
|
|
</div>
|
|
</div>
|
|
<label>Custom End Time (optional)
|
|
<span class="text-danger pull-right">{{error.endPosition}}</span>
|
|
</label>
|
|
<div class="form-row mb-3">
|
|
<div class="col">
|
|
<input class="form-control form-control-sm" type="text" ng-model="timeInput.end" placeholder="MM:SS (leave blank for end)">
|
|
<small class="form-text text-muted">Format: minutes:seconds (e.g. 10:45)</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-sm btn-link" ng-click="program = null">Cancel</button>
|
|
<button type="button" class="btn btn-sm btn-primary" ng-click="finished(program);">Done</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div> |