use of net.pms.dlna.virtual.VirtualFolder in project UniversalMediaServer by UniversalMediaServer.
the class DLNAResource method addDynamicPls.
private void addDynamicPls(final DLNAResource child) {
final DLNAResource dynPls = PMS.get().getDynamicPls();
if (dynPls == child || child.getParent() == dynPls) {
return;
}
if (child instanceof VirtualVideoAction) {
// ignore these
return;
}
if (dynamicPls == null) {
dynamicPls = new VirtualFolder(Messages.getString("PMS.147"), null);
addChildInternal(dynamicPls);
dynamicPls.addChild(dynPls);
}
if (dynamicPls != null) {
String str = Messages.getString("PluginTab.9") + " " + child.getDisplayName() + " " + Messages.getString("PMS.148");
VirtualVideoAction vva = new VirtualVideoAction(str, true) {
@Override
public boolean enable() {
PMS.get().getDynamicPls().add(child);
return true;
}
};
vva.setParent(this);
dynamicPls.addChildInternal(vva);
}
}
use of net.pms.dlna.virtual.VirtualFolder in project UniversalMediaServer by UniversalMediaServer.
the class DLNAResource method addChild.
public void addChild(DLNAResource child, boolean isNew) {
// child may be null (spotted - via rootFolder.addChild() - in a misbehaving plugin
if (child == null) {
LOGGER.error("A plugin has attempted to add a null child to \"{}\"", getName());
LOGGER.debug("Error info:", new NullPointerException("Invalid DLNA resource"));
return;
}
child.parent = this;
child.masterParent = masterParent;
if (parent != null) {
defaultRenderer = parent.getDefaultRenderer();
}
if (PMS.filter(defaultRenderer, child)) {
LOGGER.debug("Resource " + child.getName() + " is filtered out for render " + defaultRenderer.getRendererName());
return;
}
if (configuration.useCode() && !PMS.get().masterCodeValid()) {
String code = PMS.get().codeDb().getCode(child);
if (StringUtils.isNotEmpty(code)) {
DLNAResource cobj = child.isCoded();
if (cobj == null || !((CodeEnter) cobj).getCode().equals(code)) {
LOGGER.debug("Resource " + child + " is coded add code folder");
CodeEnter ce = new CodeEnter(child);
ce.parent = this;
ce.defaultRenderer = this.getDefaultRenderer();
ce.setCode(code);
addChildInternal(ce);
return;
}
}
}
try {
if (child.isValid()) {
if (child.format != null) {
// Do not add unsupported media formats to the list
if (defaultRenderer != null && !defaultRenderer.supportsFormat(child.format)) {
LOGGER.trace("Ignoring file \"{}\" because it is not supported by renderer \"{}\"", child.getName(), defaultRenderer.getRendererName());
children.remove(child);
return;
}
// Hide watched videos depending user preference
if (FullyPlayed.isHideFullyPlayed(child)) {
LOGGER.trace("Ignoring video file \"{}\" because it has been watched", child.getName());
return;
}
}
LOGGER.trace("{} child \"{}\" with class \"{}\"", isNew ? "Adding new" : "Updating", child.getName(), child.getClass().getSimpleName());
if (allChildrenAreFolders && !child.isFolder()) {
allChildrenAreFolders = false;
}
child.resHash = Math.abs(child.getSystemName().hashCode() + resumeHash());
DLNAResource resumeRes = null;
boolean addResumeFile = false;
ResumeObj r = ResumeObj.create(child);
if (r != null) {
resumeRes = child.clone();
resumeRes.resume = r;
resumeRes.resHash = child.resHash;
addResumeFile = true;
}
if (child.format != null) {
// - we have media info (via parserV2, playback info, or a plugin)
if (child.format.transcodable() || child.media != null) {
if (child.media == null) {
child.media = new DLNAMediaInfo();
}
// Try to determine a player to use for transcoding.
Player playerTranscoding = null;
// First, try to match a player from recently played folder or based on the name of the DLNAResource
// or its parent. If the name ends in "[unique player id]", that player
// is preferred.
String name = getName();
if (configuration.isShowRecentlyPlayedFolder()) {
playerTranscoding = child.player;
} else {
for (Player p : PlayerFactory.getPlayers()) {
String end = "[" + p.id() + "]";
if (name.endsWith(end)) {
nametruncate = name.lastIndexOf(end);
playerTranscoding = p;
LOGGER.trace("Selecting player based on name end");
break;
} else if (parent != null && parent.getName().endsWith(end)) {
parent.nametruncate = parent.getName().lastIndexOf(end);
playerTranscoding = p;
LOGGER.trace("Selecting player based on parent name end");
break;
}
}
}
// match a player based on media information and format.
if (playerTranscoding == null || (hasExternalSubtitles() && defaultRenderer.isSubtitlesStreamingSupported())) {
playerTranscoding = child.resolvePlayer(defaultRenderer);
}
child.setPlayer(playerTranscoding);
child.setPreferredMimeType(defaultRenderer);
if (resumeRes != null) {
resumeRes.player = playerTranscoding;
}
if (!allChildrenAreFolders) {
child.setDefaultRenderer(defaultRenderer);
// Should the child be added to the #--TRANSCODE--# folder?
if ((child.format.isVideo() || child.format.isAudio()) && child.isTranscodeFolderAvailable()) {
// true: create (and append) the #--TRANSCODE--# folder to this
// folder if supported/enabled and if it doesn't already exist
VirtualFolder transcodeFolder = getTranscodeFolder(true);
if (transcodeFolder != null) {
VirtualFolder fileTranscodeFolder = new FileTranscodeVirtualFolder(child.getDisplayName(), null);
DLNAResource newChild = child.clone();
newChild.player = playerTranscoding;
newChild.media = child.media;
fileTranscodeFolder.addChildInternal(newChild);
LOGGER.trace("Adding \"{}\" to transcode folder for player: \"{}\"", child.getName(), playerTranscoding);
transcodeFolder.updateChild(fileTranscodeFolder);
}
}
if (child.format.isVideo() && child.isSubSelectable() && !(this instanceof SubSelFile)) {
VirtualFolder vf = getSubSelector(true);
if (vf != null) {
DLNAResource newChild = child.clone();
newChild.player = playerTranscoding;
newChild.media = child.media;
LOGGER.trace("Duplicate subtitle " + child.getName() + " with player: " + playerTranscoding);
vf.addChild(new SubSelFile(newChild));
}
}
if (configuration.isDynamicPls() && !child.isFolder() && defaultRenderer != null && !defaultRenderer.isNoDynPlsFolder()) {
addDynamicPls(child);
}
for (ExternalListener listener : ExternalFactory.getExternalListeners()) {
if (listener instanceof AdditionalResourceFolderListener) {
try {
((AdditionalResourceFolderListener) listener).addAdditionalFolder(this, child);
} catch (Throwable t) {
LOGGER.error("Failed to add additional folder for listener of type: \"{}\"", listener.getClass(), t);
}
}
}
} else if (!child.format.isCompatible(child.media, defaultRenderer) && !child.isFolder()) {
LOGGER.trace("Ignoring file \"{}\" because it is not compatible with renderer \"{}\"", child.getName(), defaultRenderer.getRendererName());
children.remove(child);
}
}
if (resumeRes != null && resumeRes.media != null) {
resumeRes.media.setThumbready(false);
}
/**
* Secondary format is currently only used to provide 24-bit FLAC to PS3 by
* sending it as a fake video. This can be made more reusable with a renderer
* config setting like Mux24BitFlacToVideo if we ever have another purpose
* for it, which I doubt we will have.
*/
if (child.format.getSecondaryFormat() != null && child.media != null && defaultRenderer != null && defaultRenderer.supportsFormat(child.format.getSecondaryFormat()) && defaultRenderer.isPS3()) {
DLNAResource newChild = child.clone();
newChild.setFormat(newChild.format.getSecondaryFormat());
LOGGER.trace("Detected secondary format \"{}\" for \"{}\"", newChild.format.toString(), newChild.getName());
newChild.first = child;
child.second = newChild;
if (!newChild.format.isCompatible(newChild.media, defaultRenderer)) {
Player playerTranscoding = PlayerFactory.getPlayer(newChild);
newChild.setPlayer(playerTranscoding);
LOGGER.trace("Secondary format \"{}\" will use player \"{}\" for \"{}\"", newChild.format.toString(), newChild.getPlayer().name(), newChild.getName());
}
if (child.media != null && child.media.isSecondaryFormatValid()) {
addChild(newChild);
LOGGER.trace("Adding secondary format \"{}\" for \"{}\"", newChild.format.toString(), newChild.getName());
} else {
LOGGER.trace("Ignoring secondary format \"{}\" for \"{}\": invalid format", newChild.format.toString(), newChild.getName());
}
}
}
if (addResumeFile && resumeRes != null) {
resumeRes.setDefaultRenderer(child.getDefaultRenderer());
addChildInternal(resumeRes);
}
if (isNew) {
addChildInternal(child);
}
}
} catch (Throwable t) {
LOGGER.error("Error adding child: \"{}\"", child.getName(), t);
child.parent = null;
children.remove(child);
}
}
use of net.pms.dlna.virtual.VirtualFolder in project UniversalMediaServer by UniversalMediaServer.
the class RootFolder method getApertureFolder.
/**
* Returns Aperture folder. Used by manageRoot, so it is usually used as
* a folder at the root folder. Only works when PMS is run on Mac OS X.
* TODO: Requirements for Aperture.
*/
private DLNAResource getApertureFolder() {
VirtualFolder res = null;
if (Platform.isMac()) {
Process process = null;
try {
process = Runtime.getRuntime().exec("defaults read com.apple.iApps ApertureLibraries");
try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
// Every line entry is one aperture library. We want all of them as a dlna folder.
String line;
res = new VirtualFolder("Aperture libraries", null);
while ((line = in.readLine()) != null) {
if (line.startsWith("(") || line.startsWith(")")) {
continue;
}
// remove extra spaces
line = line.trim();
// remove quotes and spaces
line = line.substring(1, line.lastIndexOf('"'));
VirtualFolder apertureLibrary = createApertureDlnaLibrary(line);
if (apertureLibrary != null) {
res.addChild(apertureLibrary);
}
}
}
} catch (IOException | XmlParseException | URISyntaxException e) {
LOGGER.error("Something went wrong with the aperture library scan: ", e);
} finally {
// Avoid zombie processes, or open stream failures
if (process != null) {
try {
// The process seems to always finish, so we can wait for it.
// If the result code is not read by parent. The process might turn into a zombie (they are real!)
process.waitFor();
} catch (InterruptedException e) {
LOGGER.warn("Interrupted while waiting for stream for process" + e.getMessage());
}
try {
process.getErrorStream().close();
} catch (Exception e) {
LOGGER.warn("Could not close stream for output process", e);
}
try {
process.getInputStream().close();
} catch (Exception e) {
LOGGER.warn("Could not close stream for output process", e);
}
try {
process.getOutputStream().close();
} catch (Exception e) {
LOGGER.warn("Could not close stream for output process", e);
}
}
}
}
return res;
}
use of net.pms.dlna.virtual.VirtualFolder in project UniversalMediaServer by UniversalMediaServer.
the class RootFolder method getiTunesFolder.
/**
* Returns iTunes folder. Used by manageRoot, so it is usually used as a
* folder at the root folder. Only works on Mac OS X or Windows.
*
* The iTunes XML is parsed fully when this method is called, so it can
* take some time for larger (+1000 albums) databases.
*
* This method does not support genius playlists and does not provide a
* media library.
*
* @see RootFolder#getiTunesFile()
*/
private DLNAResource getiTunesFolder() {
DLNAResource res = null;
if (Platform.isMac() || Platform.isWindows()) {
Map<String, Object> iTunesLib;
List<?> Playlists;
Map<?, ?> Playlist;
Map<?, ?> Tracks;
Map<?, ?> track;
List<?> PlaylistTracks;
try {
String iTunesFile = getiTunesFile();
if (iTunesFile != null && (new File(iTunesFile)).exists()) {
// loads the (nested) properties.
iTunesLib = Plist.load(URLDecoder.decode(iTunesFile, System.getProperty("file.encoding")));
// the list of tracks
Tracks = (Map<?, ?>) iTunesLib.get("Tracks");
// the list of Playlists
Playlists = (List<?>) iTunesLib.get("Playlists");
res = new VirtualFolder("iTunes Library", null);
VirtualFolder playlistsFolder = null;
for (Object item : Playlists) {
Playlist = (Map<?, ?>) item;
if (Playlist.containsKey("Visible") && Playlist.get("Visible").equals(Boolean.FALSE)) {
continue;
}
if (Playlist.containsKey("Music") && Playlist.get("Music").equals(Boolean.TRUE)) {
// Create virtual folders for artists, albums and genres
VirtualFolder musicFolder = new VirtualFolder(Playlist.get("Name").toString(), null);
res.addChild(musicFolder);
VirtualFolder virtualFolderArtists = new VirtualFolder(Messages.getString("FoldTab.50"), null);
VirtualFolder virtualFolderAlbums = new VirtualFolder(Messages.getString("FoldTab.51"), null);
VirtualFolder virtualFolderGenres = new VirtualFolder(Messages.getString("FoldTab.52"), null);
VirtualFolder virtualFolderAllTracks = new VirtualFolder(Messages.getString("PMS.11"), null);
// list of tracks in a playlist
PlaylistTracks = (List<?>) Playlist.get("Playlist Items");
String artistName;
String albumName;
String genreName;
if (PlaylistTracks != null) {
for (Object t : PlaylistTracks) {
Map<?, ?> td = (Map<?, ?>) t;
track = (Map<?, ?>) Tracks.get(td.get("Track ID").toString());
if (track != null && track.get("Location") != null && track.get("Location").toString().startsWith("file://")) {
String name = Normalizer.normalize((String) track.get("Name"), Normalizer.Form.NFC);
// remove dots from name to prevent media renderer from trimming
name = name.replace('.', '-');
if (track.containsKey("Protected") && track.get("Protected").equals(Boolean.TRUE)) {
name = String.format(Messages.getString("RootFolder.1"), name);
}
boolean isCompilation = (track.containsKey("Compilation") && track.get("Compilation").equals(Boolean.TRUE));
artistName = (String) track.get("Artist");
if (isCompilation) {
artistName = "Compilation";
} else if (track.containsKey("Album Artist")) {
artistName = (String) track.get("Album Artist");
}
albumName = (String) track.get("Album");
genreName = (String) track.get("Genre");
if (artistName == null) {
artistName = "Unknown Artist";
} else {
artistName = Normalizer.normalize(artistName, Normalizer.Form.NFC);
}
if (albumName == null) {
albumName = "Unknown Album";
} else {
albumName = Normalizer.normalize(albumName, Normalizer.Form.NFC);
}
if (genreName == null || "".equals(genreName.replaceAll("[^a-zA-Z]", ""))) {
// This prevents us from adding blank or numerical genres
genreName = "Unknown Genre";
} else {
genreName = Normalizer.normalize(genreName, Normalizer.Form.NFC);
}
// Replace   with space and then trim
artistName = artistName.replace('\u0160', ' ').trim();
albumName = albumName.replace('\u0160', ' ').trim();
genreName = genreName.replace('\u0160', ' ').trim();
URI tURI2 = new URI(track.get("Location").toString());
File refFile = new File(URLDecoder.decode(tURI2.toURL().getFile(), "UTF-8"));
RealFile file = new RealFile(refFile, name);
// Put the track into the artist's album folder and the artist's "All tracks" folder
{
VirtualFolder individualArtistFolder = null;
VirtualFolder individualArtistAllTracksFolder;
VirtualFolder individualArtistAlbumFolder = null;
for (DLNAResource artist : virtualFolderArtists.getChildren()) {
if (areNamesEqual(artist.getName(), artistName)) {
individualArtistFolder = (VirtualFolder) artist;
for (DLNAResource album : individualArtistFolder.getChildren()) {
if (areNamesEqual(album.getName(), albumName)) {
individualArtistAlbumFolder = (VirtualFolder) album;
}
}
break;
}
}
if (individualArtistFolder == null) {
individualArtistFolder = new VirtualFolder(artistName, null);
virtualFolderArtists.addChild(individualArtistFolder);
individualArtistAllTracksFolder = new VirtualFolder(Messages.getString("PMS.11"), null);
individualArtistFolder.addChild(individualArtistAllTracksFolder);
} else {
individualArtistAllTracksFolder = (VirtualFolder) individualArtistFolder.getChildren().get(0);
}
if (individualArtistAlbumFolder == null) {
individualArtistAlbumFolder = new VirtualFolder(albumName, null);
individualArtistFolder.addChild(individualArtistAlbumFolder);
}
individualArtistAlbumFolder.addChild(file.clone());
individualArtistAllTracksFolder.addChild(file);
}
// Put the track into its album folder
{
if (!isCompilation) {
albumName += " - " + artistName;
}
VirtualFolder individualAlbumFolder = null;
for (DLNAResource album : virtualFolderAlbums.getChildren()) {
if (areNamesEqual(album.getName(), albumName)) {
individualAlbumFolder = (VirtualFolder) album;
break;
}
}
if (individualAlbumFolder == null) {
individualAlbumFolder = new VirtualFolder(albumName, null);
virtualFolderAlbums.addChild(individualAlbumFolder);
}
individualAlbumFolder.addChild(file.clone());
}
// Put the track into its genre folder
{
VirtualFolder individualGenreFolder = null;
for (DLNAResource genre : virtualFolderGenres.getChildren()) {
if (areNamesEqual(genre.getName(), genreName)) {
individualGenreFolder = (VirtualFolder) genre;
break;
}
}
if (individualGenreFolder == null) {
individualGenreFolder = new VirtualFolder(genreName, null);
virtualFolderGenres.addChild(individualGenreFolder);
}
individualGenreFolder.addChild(file.clone());
}
// Put the track into the global "All tracks" folder
virtualFolderAllTracks.addChild(file.clone());
}
}
}
musicFolder.addChild(virtualFolderArtists);
musicFolder.addChild(virtualFolderAlbums);
musicFolder.addChild(virtualFolderGenres);
musicFolder.addChild(virtualFolderAllTracks);
// Sort the virtual folders alphabetically
Collections.sort(virtualFolderArtists.getChildren(), new Comparator<DLNAResource>() {
@Override
public int compare(DLNAResource o1, DLNAResource o2) {
VirtualFolder a = (VirtualFolder) o1;
VirtualFolder b = (VirtualFolder) o2;
return a.getName().compareToIgnoreCase(b.getName());
}
});
Collections.sort(virtualFolderAlbums.getChildren(), new Comparator<DLNAResource>() {
@Override
public int compare(DLNAResource o1, DLNAResource o2) {
VirtualFolder a = (VirtualFolder) o1;
VirtualFolder b = (VirtualFolder) o2;
return a.getName().compareToIgnoreCase(b.getName());
}
});
Collections.sort(virtualFolderGenres.getChildren(), new Comparator<DLNAResource>() {
@Override
public int compare(DLNAResource o1, DLNAResource o2) {
VirtualFolder a = (VirtualFolder) o1;
VirtualFolder b = (VirtualFolder) o2;
return a.getName().compareToIgnoreCase(b.getName());
}
});
} else {
// Add all playlists
VirtualFolder pf = new VirtualFolder(Playlist.get("Name").toString(), null);
// list of tracks in a playlist
PlaylistTracks = (List<?>) Playlist.get("Playlist Items");
if (PlaylistTracks != null) {
for (Object t : PlaylistTracks) {
Map<?, ?> td = (Map<?, ?>) t;
track = (Map<?, ?>) Tracks.get(td.get("Track ID").toString());
if (track != null && track.get("Location") != null && track.get("Location").toString().startsWith("file://")) {
String name = Normalizer.normalize(track.get("Name").toString(), Normalizer.Form.NFC);
// remove dots from name to prevent media renderer from trimming
name = name.replace('.', '-');
if (track.containsKey("Protected") && track.get("Protected").equals(Boolean.TRUE)) {
name = String.format(Messages.getString("RootFolder.1"), name);
}
URI tURI2 = new URI(track.get("Location").toString());
RealFile file = new RealFile(new File(URLDecoder.decode(tURI2.toURL().getFile(), "UTF-8")), name);
pf.addChild(file);
}
}
}
int kind = Playlist.containsKey("Distinguished Kind") ? ((Number) Playlist.get("Distinguished Kind")).intValue() : -1;
if (kind >= 0 && kind != 17 && kind != 19 && kind != 20) {
// System folder, but not voice memos (17) and purchased items (19 & 20)
res.addChild(pf);
} else {
// User playlist or playlist folder
if (playlistsFolder == null) {
playlistsFolder = new VirtualFolder("Playlists", null);
res.addChild(playlistsFolder);
}
playlistsFolder.addChild(pf);
}
}
}
} else {
LOGGER.info("Could not find the iTunes file");
}
} catch (Exception e) {
LOGGER.error("Something went wrong with the iTunes Library scan: ", e);
}
}
return res;
}
use of net.pms.dlna.virtual.VirtualFolder in project UniversalMediaServer by UniversalMediaServer.
the class RootFolder method createApertureDlnaLibrary.
private VirtualFolder createApertureDlnaLibrary(String url) throws UnsupportedEncodingException, MalformedURLException, XmlParseException, IOException, URISyntaxException {
VirtualFolder res = null;
if (url != null) {
Map<String, Object> iPhotoLib;
// every project is a album, too
List<?> listOfAlbums;
Map<?, ?> album;
Map<?, ?> photoList;
URI tURI = new URI(url);
// loads the (nested) properties.
iPhotoLib = Plist.load(URLDecoder.decode(tURI.toURL().getFile(), System.getProperty("file.encoding")));
// the list of photos
photoList = (Map<?, ?>) iPhotoLib.get("Master Image List");
final Object mediaPath = iPhotoLib.get("Archive Path");
String mediaName;
if (mediaPath != null) {
mediaName = mediaPath.toString();
if (mediaName != null && mediaName.lastIndexOf('/') != -1 && mediaName.lastIndexOf(".aplibrary") != -1) {
mediaName = mediaName.substring(mediaName.lastIndexOf('/'), mediaName.lastIndexOf(".aplibrary"));
} else {
mediaName = "unknown library";
}
} else {
mediaName = "unknown library";
}
LOGGER.info("Going to parse aperture library: " + mediaName);
res = new VirtualFolder(mediaName, null);
// the list of events (rolls)
listOfAlbums = (List<?>) iPhotoLib.get("List of Albums");
for (Object item : listOfAlbums) {
album = (Map<?, ?>) item;
if (album.get("Parent") == null) {
VirtualFolder vAlbum = createApertureAlbum(photoList, album, listOfAlbums);
res.addChild(vAlbum);
}
}
} else {
LOGGER.info("No Aperture library found.");
}
return res;
}
Aggregations