Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUI for web streams/feeds management #1603

Merged
merged 10 commits into from Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/main/java/net/pms/PMS.java
Expand Up @@ -694,7 +694,7 @@ public void configurationChanged(ConfigurationEvent event) {
// file AFTER plugins are started
if (!isHeadless()) {
// but only if we got a GUI of course
((LooksFrame)frame).getPt().init();
((LooksFrame) frame).getPluginsTab().init();
}

boolean binding = false;
Expand Down Expand Up @@ -935,13 +935,13 @@ public File[] getSharedFoldersArray(boolean monitored, ArrayList<String> tags, P
if (!file.isDirectory()) {
LOGGER.warn(
"The file \"{}\" is not a folder! Please remove it from your shared folders list on the \"{}\" tab or in the configuration file.",
folder, Messages.getString("LooksFrame.22")
folder, Messages.getString("LooksFrame.TabSharedContent")
);
}
} else {
LOGGER.warn(
"The folder \"{}\" does not exist. Please remove it from your shared folders list on the \"{}\" tab or in the configuration file.",
folder, Messages.getString("LooksFrame.22")
folder, Messages.getString("LooksFrame.TabSharedContent")
);
}

Expand Down
75 changes: 75 additions & 0 deletions src/main/java/net/pms/configuration/PmsConfiguration.java
Expand Up @@ -31,7 +31,11 @@
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.swing.JOptionPane;
Expand Down Expand Up @@ -4354,4 +4358,75 @@ public boolean isInfoDbRetry() {
public int getAliveDelay() {
return getInt(KEY_ALIVE_DELAY, 0);
}

public List<String> getWebConfigurationFileHeader() {
return Arrays.asList(
"##########################################################################################################",
"# #",
"# WEB.conf: configure support for web feeds and streams #",
"# #",
"# NOTE: This file must be placed in the profile directory to work: #",
"# #",
"# http://www.ps3mediaserver.org/forum/viewtopic.php?f=6&t=3507&p=32731#p32731 #",
"# #",
"# Supported types: #",
"# #",
"# imagefeed, audiofeed, videofeed, audiostream, videostream #",
"# #",
"# Format for feeds: #",
"# #",
"# type.folders,separated,by,commas=URL #",
"# #",
"# Format for streams: #",
"# #",
"# type.folders,separated,by,commas=name for audio/video stream,URL,optional thumbnail URL #",
"# #",
"# For more web feed/stream options, see: #",
"# #",
"# http://www.ps3mediaserver.org/forum/viewtopic.php?f=6&t=3507&p=37084#p37084 #",
"# http://www.ps3mediaserver.org/forum/viewtopic.php?f=6&t=8776&p=46696#p46696 #",
"# #",
"##########################################################################################################"
);
}

public void writeWebConfigurationFile() {
List<String> defaultWebConfContents = new ArrayList<>();
defaultWebConfContents.addAll(getWebConfigurationFileHeader());
defaultWebConfContents.addAll(Arrays.asList(
"",
"# image feeds",
"imagefeed.Web,Pictures=http://api.flickr.com/services/feeds/photos_public.gne?id=29142919@N07&lang=en-en&format=rss_200",
"imagefeed.Web,Pictures=http://picasaweb.google.fr/data/feed/base/user/nefuisalbum/albumid/5218433104757705489?alt=rss&kind=photo&hl=en_US",
"imagefeed.Web,Pictures=http://picasaweb.google.fr/data/feed/base/user/cookiejarconfessionals/albumid/5229065014037788129?alt=rss&kind=photo&hl=en",
"imagefeed.Web,Pictures,Albums=http://picasaweb.google.com/data/feed/base/user/FenderStratRocker?alt=rss&kind=album&hl=en_US&access=public",
"",
"# audio feeds",
"audiofeed.Web,Podcasts=http://podcasts.engadget.com/rss.xml",
"",
"# video feeds",
"videofeed.Web,TED=http://feeds.feedburner.com/tedtalks_video",
"videofeed.Web,The Onion=http://feeds.theonion.com/onionnewsnetwork",
"",
"# video streams",
"videostream.Web,TV=France 24,mms://stream1.france24.yacast.net/f24_liveen,http://www.france24.com/en/sites/france24.com.en/themes/france24/logo-fr.png",
"videostream.Web,TV=BFM TV (French TV),mms://vipmms9.yacast.net/bfm_bfmtv,http://upload.wikimedia.org/wikipedia/en/6/62/BFMTV.png",
"videostream.Web,Webcams=View of Shanghai Harbour,mmst://www.onedir.com/cam3,http://media-cdn.tripadvisor.com/media/photo-s/00/1d/4b/d8/pudong-from-the-bund.jpg")
);

writeWebConfigurationFile(defaultWebConfContents);
}

public void writeWebConfigurationFile(List<String> fileContents) {
List<String> contentsToWrite = new ArrayList<>();
contentsToWrite.addAll(getWebConfigurationFileHeader());
contentsToWrite.addAll(fileContents);

try {
Path webConfFilePath = Paths.get(getWebConfPath());
Files.write(webConfFilePath, contentsToWrite, Charset.forName("UTF-8"));
} catch (IOException e) {
LOGGER.debug("An error occurred while writing the web config file: {}", e);
}
}
}
4 changes: 2 additions & 2 deletions src/main/java/net/pms/dlna/DLNAMediaDatabase.java
Expand Up @@ -44,7 +44,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.pms.newgui.NavigationShareTab;
import net.pms.newgui.SharedContentTab;

/**
* This class provides methods for creating and maintaining the database where
Expand Down Expand Up @@ -1378,7 +1378,7 @@ public void scanLibrary() {
scanner = new Thread(this, "Library Scanner");
scanner.setPriority(scanner.MIN_PRIORITY);
scanner.start();
NavigationShareTab.setScanLibraryBusy();
SharedContentTab.setScanLibraryBusy();
}
}

Expand Down
69 changes: 48 additions & 21 deletions src/main/java/net/pms/dlna/RootFolder.java
Expand Up @@ -43,6 +43,7 @@
import net.pms.formats.Format;
import net.pms.io.StreamGobbler;
import net.pms.newgui.IFrame;
import net.pms.newgui.SharedContentTab;
import net.pms.util.CodeDb;
import net.pms.util.FileUtil;
import net.pms.util.FileWatcher;
Expand Down Expand Up @@ -371,22 +372,34 @@ private List<DLNAResource> getVirtualFolders(ArrayList<String> tags) {
return res;
}

private void loadWebConf() {
/**
* Removes all web folders, re-parses the web config file, and adds a
* file watcher for the file.
*/
public void loadWebConf() {
for (DLNAResource d : webFolders) {
getChildren().remove(d);
}
webFolders.clear();
String webConfPath = configuration.getWebConfPath();
File webConf = new File(webConfPath);
if (webConf.exists() && configuration.getExternalNetwork() && !configuration.isHideWebFolder(tags)) {
addWebFolder(webConf);
parseWebConf(webConf);
FileWatcher.add(new FileWatcher.Watch(webConf.getPath(), rootWatcher, this, RELOAD_WEB_CONF));
}
setLastModified(1);
}

private void addWebFolder(File webConf) {
/**
* This parses the web config and populates the virtual Web folder.
*
* @param webConf
*/
private void parseWebConf(File webConf) {
try {
// Remove any existing rows from the Web content GUI
((SharedContentTab.WebContentTableModel) SharedContentTab.webContentList.getModel()).setRowCount(0);

try (LineNumberReader br = new LineNumberReader(new InputStreamReader(new FileInputStream(webConf), StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
Expand All @@ -396,20 +409,23 @@ private void addWebFolder(File webConf) {
String key = line.substring(0, line.indexOf('='));
String value = line.substring(line.indexOf('=') + 1);
String[] keys = parseFeedKey(key);
String sourceType = keys[0];
String folderName = keys[1] == null ? null : keys[1];

try {
if (
keys[0].equals("imagefeed") ||
keys[0].equals("audiofeed") ||
keys[0].equals("videofeed") ||
keys[0].equals("audiostream") ||
keys[0].equals("videostream")
sourceType.equals("imagefeed") ||
sourceType.equals("audiofeed") ||
sourceType.equals("videofeed") ||
sourceType.equals("audiostream") ||
sourceType.equals("videostream")
) {
String[] values = parseFeedValue(value);
String uri = values[0];
DLNAResource parent = null;

if (keys[1] != null) {
StringTokenizer st = new StringTokenizer(keys[1], ",");
if (folderName != null) {
StringTokenizer st = new StringTokenizer(folderName, ",");
DLNAResource currentRoot = this;

while (st.hasMoreTokens()) {
Expand All @@ -432,33 +448,44 @@ private void addWebFolder(File webConf) {
if (parent == null) {
parent = this;
}
if (keys[0].endsWith("stream")) {
int type = keys[0].startsWith("audio") ? Format.AUDIO : Format.VIDEO;
DLNAResource playlist = PlaylistFolder.getPlaylist(values[0], values[1], type);

if (sourceType.endsWith("stream")) {
int type = sourceType.startsWith("audio") ? Format.AUDIO : Format.VIDEO;
DLNAResource playlist = PlaylistFolder.getPlaylist(uri, values[1], type);
if (playlist != null) {
parent.addChild(playlist);
continue;
}
}
switch (keys[0]) {

String readableType = "";
switch (sourceType) {
case "imagefeed":
parent.addChild(new ImagesFeed(values[0]));
readableType = "Image feed";
parent.addChild(new ImagesFeed(uri));
break;
case "videofeed":
parent.addChild(new VideosFeed(values[0]));
readableType = "Video feed";
parent.addChild(new VideosFeed(uri));
break;
case "audiofeed":
parent.addChild(new AudiosFeed(values[0]));
readableType = "Podcast";
parent.addChild(new AudiosFeed(uri));
break;
case "audiostream":
parent.addChild(new WebAudioStream(values[0], values[1], values[2]));
readableType = "Audio stream";
parent.addChild(new WebAudioStream(uri, values[1], values[2]));
break;
case "videostream":
parent.addChild(new WebVideoStream(values[0], values[1], values[2]));
readableType = "Video stream";
parent.addChild(new WebVideoStream(uri, values[1], values[2]));
break;
default:
break;
}

// Update the GUI on the Shared Content tab
SharedContentTab.webContentTableModel.addRow(new Object[]{readableType, folderName, uri});
}
} catch (ArrayIndexOutOfBoundsException e) {
// catch exception here and go with parsing
Expand All @@ -483,7 +510,7 @@ private void addWebFolder(File webConf) {
* @param spec (String) to be split
* @return Array of (String) that represents the tokenized entry.
*/
private String[] parseFeedKey(String spec) {
public static String[] parseFeedKey(String spec) {
String[] pair = StringUtils.split(spec, ".", 2);

if (pair == null || pair.length < 2) {
Expand All @@ -504,7 +531,7 @@ private String[] parseFeedKey(String spec) {
* @param spec (String) to be split
* @return Array of (String) that represents the tokenized entry.
*/
private String[] parseFeedValue(String spec) {
public static String[] parseFeedValue(String spec) {
StringTokenizer st = new StringTokenizer(spec, ",");
String[] triple = new String[3];
int i = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/net/pms/external/ExternalFactory.java
Expand Up @@ -274,7 +274,7 @@ private static void purgeCode(String mainClass, URL newUrl) {
externalListeners.remove(remove);
remove.shutdown();
LooksFrame frame = (LooksFrame) PMS.get().getFrame();
frame.getPt().removePlugin(remove);
frame.getPluginsTab().removePlugin(remove);
}

for (int i = 0; i < 3; i++) {
Expand Down Expand Up @@ -507,7 +507,7 @@ public static void instantiateDownloaded(JLabel update) {
if (PMS.get().getFrame() instanceof LooksFrame) {
LooksFrame frame = (LooksFrame) PMS.get().getFrame();

if (!frame.getPt().appendPlugin(instance)) {
if (!frame.getPluginsTab().appendPlugin(instance)) {
LOGGER.warn("Plugin limit of 30 has been reached");
}
}
Expand Down
44 changes: 25 additions & 19 deletions src/main/java/net/pms/newgui/LooksFrame.java
Expand Up @@ -88,13 +88,14 @@ public class LooksFrame extends JFrame implements IFrame, Observer {
null
};

private NavigationShareTab nt;
private NavigationShareTab navigationSettingsTab;
private SharedContentTab sharedContentTab;
private StatusTab st;
private TracesTab tt;
private TranscodingTab tr;
private GeneralTab gt;
private GeneralTab generalSettingsTab;
private HelpTab ht;
private PluginTab pt;
private PluginTab pluginsTab;
private final JAnimatedButton reload = createAnimatedToolBarButton(Messages.getString("LooksFrame.12"), "button-restart.png");;
private final AnimatedIcon restartRequredIcon = new AnimatedIcon(
reload, true, AnimatedIcon.buildAnimation("button-restart-requiredF%d.png", 0, 24, true, 800, 300, 15)
Expand All @@ -121,24 +122,27 @@ public TracesTab getTt() {
return tt;
}

public NavigationShareTab getNt() {
return nt;
public NavigationShareTab getNavigationSettingsTab() {
return navigationSettingsTab;
}

public SharedContentTab getSharedContentTab() {
return sharedContentTab;
}

public TranscodingTab getTr() {
return tr;
}

public GeneralTab getGt() {
return gt;
public GeneralTab getGeneralSettingsTab() {
return generalSettingsTab;
}

public PluginTab getPt() {
return pt;
public PluginTab getPluginsTab() {
return pluginsTab;
}

public static void initializeLookAndFeel() {

synchronized (lookAndFeelInitializedLock) {
if (lookAndFeelInitialized) {
return;
Expand Down Expand Up @@ -496,17 +500,19 @@ public JComponent buildMain() {

st = new StatusTab(configuration);
tt = new TracesTab(configuration, this);
gt = new GeneralTab(configuration, this);
pt = new PluginTab(configuration, this);
nt = new NavigationShareTab(configuration, this);
generalSettingsTab = new GeneralTab(configuration, this);
pluginsTab = new PluginTab(configuration, this);
navigationSettingsTab = new NavigationShareTab(configuration, this);
sharedContentTab = new SharedContentTab(configuration, this);
tr = new TranscodingTab(configuration, this);
ht = new HelpTab();

tabbedPane.addTab(Messages.getString("LooksFrame.18"), st.build());
tabbedPane.addTab(Messages.getString("LooksFrame.19"), tt.build());
tabbedPane.addTab(Messages.getString("LooksFrame.20"), gt.build());
tabbedPane.addTab(Messages.getString("LooksFrame.27"), pt.build());
tabbedPane.addTab(Messages.getString("LooksFrame.22"), nt.build());
tabbedPane.addTab(Messages.getString("LooksFrame.TabGeneralSettings"), generalSettingsTab.build());
tabbedPane.addTab(Messages.getString("LooksFrame.TabPlugins"), pluginsTab.build());
tabbedPane.addTab(Messages.getString("LooksFrame.TabNavigationSettings"), navigationSettingsTab.build());
tabbedPane.addTab(Messages.getString("LooksFrame.TabSharedContent"), sharedContentTab.build());
if (!configuration.isDisableTranscoding()) {
tabbedPane.addTab(Messages.getString("LooksFrame.21"), tr.build());
} else {
Expand Down Expand Up @@ -703,13 +709,13 @@ public void updateRenderer(RendererConfiguration renderer) {
@Override
public void serverReady() {
st.updateMemoryUsage();
gt.addRenderers();
pt.addPlugins();
generalSettingsTab.addRenderers();
pluginsTab.addPlugins();
}

@Override
public void setScanLibraryEnabled(boolean flag) {
getNt().setScanLibraryEnabled(flag);
getSharedContentTab().setScanLibraryEnabled(flag);
}

@Override
Expand Down