Skip to content

Commit

Permalink
Add custom / private emby functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
theotherp committed Jan 24, 2025
1 parent b96138e commit 0b4cd4d
Show file tree
Hide file tree
Showing 13 changed files with 270 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public void replace(BaseConfig newConfig, boolean fireConfigChangedEvent) {
baseConfig.setAuth(newConfig.getAuth());
baseConfig.setGenericStorage(newConfig.getGenericStorage());
baseConfig.setNotificationConfig(newConfig.getNotificationConfig());
baseConfig.setEmby(newConfig.getEmby());


if (fireConfigChangedEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ public class SafeConfig {
private SafeDownloadingConfig downloading;
private SafeLoggingConfig logging;
private SafeNotificationConfig notificationConfig;
private SafeEmbyConfig emby;
private boolean showNews;
private boolean keepHistory;


private List<SafeIndexerConfig> indexers;

public SafeConfig(BaseConfig baseConfig) {
Expand All @@ -33,8 +35,10 @@ public SafeConfig(BaseConfig baseConfig) {
this.indexers = baseConfig.getIndexers().stream().map(indexerConfig -> new SafeIndexerConfig(indexerConfig, baseConfig)).collect(Collectors.toList());
this.categoriesConfig = new SafeCategoriesConfig(baseConfig.getCategoriesConfig());
this.notificationConfig = new SafeNotificationConfig(baseConfig.getNotificationConfig());
this.emby = new SafeEmbyConfig(baseConfig.getEmby());
this.showNews = baseConfig.getMain().isShowNews();
this.keepHistory = baseConfig.getMain().isKeepHistory();

}

public String getAuthType() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.nzbhydra.config.safeconfig;

import lombok.Getter;
import org.nzbhydra.config.emby.EmbyConfig;


@Getter
public class SafeEmbyConfig {

private final String embyBaseUrl;
private final String embyApiKey;

public SafeEmbyConfig(EmbyConfig embyConfig) {
embyBaseUrl = embyConfig.getEmbyBaseUrl();
embyApiKey = embyConfig.getEmbyApiKey();
}

}
87 changes: 87 additions & 0 deletions core/src/main/java/org/nzbhydra/emby/EmbyWeb.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* (C) Copyright 2025 TheOtherP ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.nzbhydra.emby;

import com.fasterxml.jackson.core.type.TypeReference;
import org.jetbrains.annotations.NotNull;
import org.nzbhydra.config.ConfigProvider;
import org.nzbhydra.mapping.emby.EmbyItemsResponse;
import org.nzbhydra.webaccess.WebAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;

@RestController
public class EmbyWeb {

private static final Logger logger = LoggerFactory.getLogger(EmbyWeb.class);

@Autowired
private WebAccess webAccess;
@Autowired
private ConfigProvider configProvider;

@Secured({"ROLE_USER"})
@RequestMapping(value = "/internalapi/emby/isSeriesAvailable", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public boolean isSeriesAvailable(@RequestParam String tvdbId) {
final String uriString = getUriBuilder()
.queryParam("IncludeItemTypes", "Series")
.queryParam("AnyProviderIdEquals", "tvdb." + tvdbId).toUriString();
try {
final EmbyItemsResponse response = webAccess.callUrl(uriString, new TypeReference<>() {
});
return response.getTotalRecordCount() > 0;
} catch (IOException e) {
logger.error("Error calling Emby API", e);
return false;
}
}

@Secured({"ROLE_USER"})
@RequestMapping(value = "/internalapi/emby/isMovieAvailable", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public boolean isMovieAvailable(@RequestParam String tmdbId) {
final String uriString = getUriBuilder()
.queryParam("IncludeItemTypes", "Movies")
.queryParam("AnyProviderIdEquals", "tmdb." + tmdbId).toUriString();
try {
final EmbyItemsResponse response = webAccess.callUrl(uriString, new TypeReference<>() {
});
return response.getTotalRecordCount() > 0;
} catch (IOException e) {
logger.error("Error calling Emby API", e);
return false;
}
}

@NotNull
private UriComponentsBuilder getUriBuilder() {
return UriComponentsBuilder.fromHttpUrl(configProvider.getBaseConfig().getEmby().getEmbyBaseUrl())
.pathSegment("emby", "Items")
.queryParam("Recursive", "true")
.queryParam("api_key", configProvider.getBaseConfig().getEmby().getEmbyApiKey());
}

}
3 changes: 3 additions & 0 deletions core/src/main/resources/config/baseConfig.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ downloading:
fallbackForFailed: BOTH
primaryDownloader: null
externalUrl: null
emby:
embyBaseUrl: null
embyApiKey: null
genericStorage: {}
indexers: []
main:
Expand Down
66 changes: 21 additions & 45 deletions core/src/main/resources/static/js/nzbhydra.js
Original file line number Diff line number Diff line change
Expand Up @@ -9819,14 +9819,14 @@ function SearchService($http) {
}
}

SearchResultsController.$inject = ["$stateParams", "$scope", "$q", "$timeout", "$document", "blockUI", "growl", "localStorageService", "SearchService", "ConfigService", "CategoriesService", "DebugService", "GenericStorageService", "ModalService", "$uibModal"];angular
SearchResultsController.$inject = ["$stateParams", "$scope", "$http", "$q", "$timeout", "$document", "blockUI", "growl", "localStorageService", "SearchService", "ConfigService", "CategoriesService", "DebugService", "GenericStorageService", "ModalService", "$uibModal"];angular
.module('nzbhydraApp')
.controller('SearchResultsController', SearchResultsController);

//SearchResultsController.$inject = ['blockUi'];
function SearchResultsController($stateParams, $scope, $q, $timeout, $document, blockUI, growl, localStorageService, SearchService, ConfigService, CategoriesService, DebugService, GenericStorageService, ModalService, $uibModal) {
function SearchResultsController($stateParams, $scope, $http, $q, $timeout, $document, blockUI, growl, localStorageService, SearchService, ConfigService, CategoriesService, DebugService, GenericStorageService, ModalService, $uibModal) {
// console.time("Presenting");
DebugService.log("foobar");

$scope.limitTo = ConfigService.getSafe().searching.loadLimitInternal;
$scope.offset = 0;
$scope.allowZipDownload = ConfigService.getSafe().downloading.fileDownloadAccessType === 'PROXY';
Expand Down Expand Up @@ -10841,53 +10841,29 @@ function SearchResultsController($stateParams, $scope, $q, $timeout, $document,
}, 1);
});

if (ConfigService.getSafe().emby.embyApiKey) {
if ($stateParams.mode === "tvsearch") {
$http.get("http://127.0.0.1:5076/internalapi/emby/isSeriesAvailable?tvdbId=" + $stateParams.tvdbId).then(function (result) {
console.log("Show already available on emby: " + result.data);
$scope.showEmbyResults = result.data;
$scope.embyType = "show";
});

} else if ($stateParams.mode === "movie") {
$http.get("http://127.0.0.1:5076/internalapi/emby/isMovieAvailable?tmdbId=" + $stateParams.tmdbId).then(function (result) {
console.log("Movie already available on emby: " + result.data);
$scope.showEmbyResults = result.data;
$scope.embyType = "movie";
});
}
}


$timeout(function () {
DebugService.print();
}, 3000);

// $timeout(function () {
// function getWatchers(root) {
// root = angular.element(root || document.documentElement);
// var watcherCount = 0;
// var ids = [];
//
// function getElemWatchers(element, ids) {
// var isolateWatchers = getWatchersFromScope(element.data().$isolateScope, ids);
// var scopeWatchers = getWatchersFromScope(element.data().$scope, ids);
// var watchers = scopeWatchers.concat(isolateWatchers);
// angular.forEach(element.children(), function (childElement) {
// watchers = watchers.concat(getElemWatchers(angular.element(childElement), ids));
// });
// return watchers;
// }
//
// function getWatchersFromScope(scope, ids) {
// if (scope) {
// if (_.indexOf(ids, scope.$id) > -1) {
// return [];
// }
// ids.push(scope.$id);
// if (scope.$$watchers) {
// if (scope.$$watchers.length > 1) {
// var a;
// a = 1;
// }
// return scope.$$watchers;
// }
// {
// return [];
// }
//
// } else {
// return [];
// }
// }
//
// return getElemWatchers(root, ids);
// }
//
// }, $scope.limitTo);

}


Expand Down
2 changes: 1 addition & 1 deletion core/src/main/resources/static/js/nzbhydra.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/src/main/resources/static/js/templates.js

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions core/ui-src/html/states/search-results.html
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,20 @@ <h2 ng-if="!anyResultsRejected && anyIndexersSearchedSuccessfully">No results we
</div>
</div>

<div class="row" ng-if="::showEmbyResults">
<div class="col-md-6"></div>
<div class="col-md-8">
<div class="alert alert-success" role="alert">
<span ng-if="embyType==='show'">
This show is already available on the server. Please check if the episodes you are interested in are available or request them using Ombi.
</span>
<span ng-if="embyType==='movie'">
This movie is already available on the server. Please check if the quality matches the one you want..
</span>
</div>
</div>
</div>

<div class="row" ng-if="::(isShowFilterButtons)">
<div class="col-md-20">
<div class="btn-toolbar" role="toolbar" style="margin: auto; display:inline-block">
Expand Down
64 changes: 20 additions & 44 deletions core/ui-src/js/search-results-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ angular
.controller('SearchResultsController', SearchResultsController);

//SearchResultsController.$inject = ['blockUi'];
function SearchResultsController($stateParams, $scope, $q, $timeout, $document, blockUI, growl, localStorageService, SearchService, ConfigService, CategoriesService, DebugService, GenericStorageService, ModalService, $uibModal) {
function SearchResultsController($stateParams, $scope, $http, $q, $timeout, $document, blockUI, growl, localStorageService, SearchService, ConfigService, CategoriesService, DebugService, GenericStorageService, ModalService, $uibModal) {
// console.time("Presenting");
DebugService.log("foobar");

$scope.limitTo = ConfigService.getSafe().searching.loadLimitInternal;
$scope.offset = 0;
$scope.allowZipDownload = ConfigService.getSafe().downloading.fileDownloadAccessType === 'PROXY';
Expand Down Expand Up @@ -1020,51 +1020,27 @@ function SearchResultsController($stateParams, $scope, $q, $timeout, $document,
}, 1);
});

if (ConfigService.getSafe().emby.embyApiKey) {
if ($stateParams.mode === "tvsearch") {
$http.get("http://127.0.0.1:5076/internalapi/emby/isSeriesAvailable?tvdbId=" + $stateParams.tvdbId).then(function (result) {
console.log("Show already available on emby: " + result.data);
$scope.showEmbyResults = result.data;
$scope.embyType = "show";
});

} else if ($stateParams.mode === "movie") {
$http.get("http://127.0.0.1:5076/internalapi/emby/isMovieAvailable?tmdbId=" + $stateParams.tmdbId).then(function (result) {
console.log("Movie already available on emby: " + result.data);
$scope.showEmbyResults = result.data;
$scope.embyType = "movie";
});
}
}


$timeout(function () {
DebugService.print();
}, 3000);

// $timeout(function () {
// function getWatchers(root) {
// root = angular.element(root || document.documentElement);
// var watcherCount = 0;
// var ids = [];
//
// function getElemWatchers(element, ids) {
// var isolateWatchers = getWatchersFromScope(element.data().$isolateScope, ids);
// var scopeWatchers = getWatchersFromScope(element.data().$scope, ids);
// var watchers = scopeWatchers.concat(isolateWatchers);
// angular.forEach(element.children(), function (childElement) {
// watchers = watchers.concat(getElemWatchers(angular.element(childElement), ids));
// });
// return watchers;
// }
//
// function getWatchersFromScope(scope, ids) {
// if (scope) {
// if (_.indexOf(ids, scope.$id) > -1) {
// return [];
// }
// ids.push(scope.$id);
// if (scope.$$watchers) {
// if (scope.$$watchers.length > 1) {
// var a;
// a = 1;
// }
// return scope.$$watchers;
// }
// {
// return [];
// }
//
// } else {
// return [];
// }
// }
//
// return getElemWatchers(root, ids);
// }
//
// }, $scope.limitTo);

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.nzbhydra.config.auth.AuthConfig;
import org.nzbhydra.config.category.CategoriesConfig;
import org.nzbhydra.config.downloading.DownloadingConfig;
import org.nzbhydra.config.emby.EmbyConfig;
import org.nzbhydra.config.indexer.IndexerConfig;
import org.nzbhydra.springnative.ReflectionMarker;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
Expand Down Expand Up @@ -56,6 +57,9 @@ public class BaseConfig {
private SearchingConfig searching = new SearchingConfig();
@NestedConfigurationProperty
private NotificationConfig notificationConfig = new NotificationConfig();
@NestedConfigurationProperty
private EmbyConfig emby = new EmbyConfig();


@DiffIgnore
private Map<String, String> genericStorage = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* (C) Copyright 2025 TheOtherP ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.nzbhydra.config.emby;

import lombok.Data;
import org.nzbhydra.springnative.ReflectionMarker;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ReflectionMarker
@ConfigurationProperties(prefix = "downloading")
public class EmbyConfig {

private String embyBaseUrl;
private String embyApiKey;

}
Loading

0 comments on commit 0b4cd4d

Please sign in to comment.