Skip to content

Commit

Permalink
GUI for web streams/feeds management (#1603)
Browse files Browse the repository at this point in the history
* WIP GUI idea for managing web stuff

* More WIP

* GUI update and translatable

* Remove unnecessary class

* Removed not used imports

* Implemented editing

* New button

* Fixed button sizes

* Change the layout of the web content adding/editing panel

* New tooltips
  • Loading branch information
SubJunk committed Oct 10, 2018
1 parent ca157ca commit 28e0d4d
Show file tree
Hide file tree
Showing 17 changed files with 972 additions and 416 deletions.
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 @@ -4344,4 +4348,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 @@ -86,13 +86,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 @@ -119,24 +120,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 @@ -488,17 +492,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 @@ -695,13 +701,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

0 comments on commit 28e0d4d

Please sign in to comment.