From 7ac129c34c4af3d075c1af35106a419a5fc53066 Mon Sep 17 00:00:00 2001 From: "Warren R. Bank" Date: Thu, 27 Oct 2022 05:28:24 -0700 Subject: [PATCH] release: '002.00.49-16API' * POST data sent in requests to "/play" and "/queue" API endpoints: - multiple lines can repeat the following key to declare more than one value: * content-location --- README.md | 8 ++++ .../constant/Constant.java | 5 ++ .../httpcore/RequestListenerThread.java | 2 +- .../service/MyMessageHandler.java | 6 +++ .../SerializedPlaylistExtractor.java | 15 ++++++ .../utils/StringUtils.java | 47 ++++++++++++++++++- android-studio-project/constants.gradle | 4 +- 7 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/playlist_extractors/SerializedPlaylistExtractor.java diff --git a/README.md b/README.md index b09d53f..db87c74 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,13 @@ __extended APIs:__ --data-binary "Content-Location: ${video_url_3}\nCaption-Location: ${caption_url_3}\nReferer: ${videos_page}\nStart-Position: 30" \ "http://${airplay_ip}/queue" ``` +* play video #1 and add videos #2 and #3 to end of queue (set 'Referer' request header): + ```bash + curl --silent -X POST \ + -H "Content-Type: text/parameters" \ + --data-binary "Content-Location: ${video_url_1}\nContent-Location: ${video_url_2}\nContent-Location: ${video_url_3}\nReferer: ${videos_page}" \ + "http://${airplay_ip}/play" + ``` * play DRM video #1 (seek to 10 seconds, end playback at 30 seconds): ```bash curl --silent -X POST \ @@ -449,6 +456,7 @@ __extended APIs:__ - keys are not case sensitive - recognized keys include: * _content-location_ + - use key on multiple lines to declare more than one value * _caption-location_ * _referer_ * _req-header_ diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/constant/Constant.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/constant/Constant.java index d8af688..cd4d8a1 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/constant/Constant.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/constant/Constant.java @@ -239,4 +239,9 @@ public interface Video_Source_Map { public static final String PLAYLIST_URLS = "playlist-urls"; } + public interface Delimiter { + public static final String DEFAULT = "\n"; + public static final String PLAYLIST_URLS = "{{<<|^|>>}}"; + } + } diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java index cdb8bd3..36d85aa 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/httpcore/RequestListenerThread.java @@ -557,7 +557,7 @@ else if ( HashMap> map = StringUtils.parseRequestBody_allowDuplicateKeys(requestBody, /* normalize_lowercase_keys= */ true); - playUrl = (String) StringUtils.getLastListItem((ArrayList) map.get("content-location")); + playUrl = (String) StringUtils.serializeURLs( (ArrayList) map.get("content-location")); textUrl = (String) StringUtils.getLastListItem((ArrayList) map.get("caption-location")); referUrl = (String) StringUtils.getLastListItem((ArrayList) map.get("referer")); useCache = (String) StringUtils.getLastListItem((ArrayList) map.get("use-cache")); diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/MyMessageHandler.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/MyMessageHandler.java index 533abbb..146cc6b 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/MyMessageHandler.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/MyMessageHandler.java @@ -10,6 +10,7 @@ import com.github.warren_bank.exoplayer_airplay_receiver.service.playlist_extractors.FileM3uPlaylistExtractor; import com.github.warren_bank.exoplayer_airplay_receiver.service.playlist_extractors.HttpHtmlPlaylistExtractor; import com.github.warren_bank.exoplayer_airplay_receiver.service.playlist_extractors.HttpM3uPlaylistExtractor; +import com.github.warren_bank.exoplayer_airplay_receiver.service.playlist_extractors.SerializedPlaylistExtractor; import com.github.warren_bank.exoplayer_airplay_receiver.ui.ImageViewerActivity; import com.github.warren_bank.exoplayer_airplay_receiver.ui.RuntimePermissionsRequestActivity; import com.github.warren_bank.exoplayer_airplay_receiver.ui.VideoPlayerActivity; @@ -44,6 +45,7 @@ final class MyMessageHandler extends Handler { private ArrayList externalStorageMessages; private HandlerThread networkingHandlerThread; + private SerializedPlaylistExtractor serializedExtractor; private HttpM3uPlaylistExtractor httpM3uExtractor; private HttpHtmlPlaylistExtractor httpHtmlExtractor; private ContentProviderM3uPlaylistExtractor contentM3uExtractor; @@ -62,6 +64,7 @@ public MyMessageHandler(Looper looper, NetworkingService service) { networkingHandlerThread = new HandlerThread("MyNetworkingThread"); networkingHandlerThread.start(); + serializedExtractor = new SerializedPlaylistExtractor(); httpM3uExtractor = new HttpM3uPlaylistExtractor(); httpHtmlExtractor = new HttpHtmlPlaylistExtractor(); contentM3uExtractor = new ContentProviderM3uPlaylistExtractor(service.getApplicationContext()); @@ -609,6 +612,9 @@ private ArrayList extractPlaylists(String uri, ArrayList playlis ArrayList matches = null; + if (matches == null) + matches = serializedExtractor.expandPlaylist(uri); + if (matches == null) matches = httpM3uExtractor.expandPlaylist(uri); //8-bit ascii diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/playlist_extractors/SerializedPlaylistExtractor.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/playlist_extractors/SerializedPlaylistExtractor.java new file mode 100644 index 0000000..f951c16 --- /dev/null +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/service/playlist_extractors/SerializedPlaylistExtractor.java @@ -0,0 +1,15 @@ +package com.github.warren_bank.exoplayer_airplay_receiver.service.playlist_extractors; + +import com.github.warren_bank.exoplayer_airplay_receiver.utils.StringUtils; + +import java.util.ArrayList; + +public class SerializedPlaylistExtractor { + public ArrayList expandPlaylist(String strUrl) { + ArrayList matches = StringUtils.deserializeURLs(strUrl); + + return ((matches == null) || (matches.size() < 2)) + ? null + : matches; + } +} diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/StringUtils.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/StringUtils.java index b7834b8..dea1fce 100644 --- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/StringUtils.java +++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/utils/StringUtils.java @@ -1,5 +1,7 @@ package com.github.warren_bank.exoplayer_airplay_receiver.utils; +import com.github.warren_bank.exoplayer_airplay_receiver.constant.Constant; + import android.os.Bundle; import android.text.TextUtils; @@ -8,9 +10,11 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.TreeMap; +import java.util.regex.Pattern; public class StringUtils { @@ -128,7 +132,7 @@ public static HashMap parseDuplicateKeyValues(List list) public static HashMap parseDuplicateKeyValues(List list, boolean normalize_lowercase_keys) { if ((list == null) || list.isEmpty()) return null; - String requestBody = TextUtils.join("\n", list); + String requestBody = StringUtils.convertListToString(list, "\n"); return StringUtils.parseRequestBody(requestBody, normalize_lowercase_keys); } @@ -168,6 +172,14 @@ public static String encodeURL(URL url) { } } + public static String serializeURLs(ArrayList list) { + return StringUtils.convertArrayListToString(list, Constant.Delimiter.PLAYLIST_URLS); + } + + public static ArrayList deserializeURLs(String text) { + return StringUtils.convertStringToArrayList(text, Pattern.quote(Constant.Delimiter.PLAYLIST_URLS)); + } + public static String toString(HashMap map) { if ((map == null) || map.isEmpty()) return null; @@ -294,6 +306,39 @@ public static ArrayList convertHashMapToArrayList(HashMap list, String delimiter_token) { + return StringUtils.convertListToString((List) list, delimiter_token); + } + + public static String convertListToString(List list, String delimiter_token) { + if ((list == null) || list.isEmpty()) return null; + + if (delimiter_token == null) + delimiter_token = Constant.Delimiter.DEFAULT; + + return TextUtils.join(delimiter_token, list); + } + + public static ArrayList convertStringToArrayList(String text, String delimiter_token) { + List list = StringUtils.convertStringToList(text, delimiter_token); + + return new ArrayList(list); + } + + public static List convertStringToList(String text, String delimiter_token) { + if (TextUtils.isEmpty(text)) return Collections.emptyList(); + + if (delimiter_token == null) + delimiter_token = Pattern.quote(Constant.Delimiter.DEFAULT); + + String[] strArray = TextUtils.split(text, delimiter_token); + List list = (List) Arrays.asList(strArray); + + return list; + } + + // =================================== + public static String repeatString(String value, int count) { return ((value != null) && (count > 0)) ? (new String(new char[count])).replace("\0", value) diff --git a/android-studio-project/constants.gradle b/android-studio-project/constants.gradle index e73875b..4d5ad25 100644 --- a/android-studio-project/constants.gradle +++ b/android-studio-project/constants.gradle @@ -1,6 +1,6 @@ project.ext { - releaseVersionCode = Integer.parseInt("002004816", 10) //Integer.MAX_VALUE == 2147483647 - releaseVersion = '002.00.48-16API' + releaseVersionCode = Integer.parseInt("002004916", 10) //Integer.MAX_VALUE == 2147483647 + releaseVersion = '002.00.49-16API' javaVersion = JavaVersion.VERSION_1_8 minSdkVersion = 16 targetSdkVersion = 29