diff --git a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java index b397990..ccd7706 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java @@ -15,9 +15,10 @@ package app.fedilab.fedilabtube; * see . */ import android.content.Context; -import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.text.InputFilter; import android.view.LayoutInflater; import android.view.MenuItem; @@ -38,13 +39,6 @@ import androidx.appcompat.app.AppCompatActivity; import com.google.android.material.floatingactionbutton.FloatingActionButton; -import net.gotev.uploadservice.MultipartUploadRequest; -import net.gotev.uploadservice.ServerResponse; -import net.gotev.uploadservice.UploadInfo; -import net.gotev.uploadservice.UploadNotificationConfig; -import net.gotev.uploadservice.UploadStatusDelegate; - -import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -55,10 +49,12 @@ import java.util.Map; import app.fedilab.fedilabtube.asynctasks.ManagePlaylistsAsyncTask; import app.fedilab.fedilabtube.asynctasks.RetrievePeertubeChannelsAsyncTask; import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.client.HttpsConnection; +import app.fedilab.fedilabtube.client.PeertubeAPI; import app.fedilab.fedilabtube.client.entities.Account; import app.fedilab.fedilabtube.client.entities.Playlist; +import app.fedilab.fedilabtube.client.entities.PlaylistElement; import app.fedilab.fedilabtube.drawer.PlaylistAdapter; -import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.interfaces.OnPlaylistActionInterface; import app.fedilab.fedilabtube.interfaces.OnRetrievePeertubeInterface; import es.dmoral.toasty.Toasty; @@ -72,15 +68,13 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis private AsyncTask asyncTask; private RelativeLayout mainLoader; - private FloatingActionButton add_new; private RelativeLayout textviewNoAction; private HashMap privacyToSend; - private HashMap channelToSend; private Spinner set_upload_channel; private Spinner set_upload_privacy; - private HashMap channels; - - + private String idChannel; + private List playlists; + PlaylistAdapter playlistAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -97,10 +91,10 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis RelativeLayout nextElementLoader = findViewById(R.id.loading_next_items); mainLoader.setVisibility(View.VISIBLE); nextElementLoader.setVisibility(View.GONE); - + idChannel = null; asyncTask = new ManagePlaylistsAsyncTask(AllPlaylistsActivity.this, ManagePlaylistsAsyncTask.action.GET_PLAYLIST, null, null, null, AllPlaylistsActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - add_new = findViewById(R.id.add_new); + FloatingActionButton add_new = findViewById(R.id.add_new); LinkedHashMap privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies()); @@ -111,8 +105,12 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis } + playlists = new ArrayList<>(); + ListView lv_playlist = findViewById(R.id.lv_playlist); + playlistAdapter = new PlaylistAdapter(AllPlaylistsActivity.this, playlists, textviewNoAction); + lv_playlist.setAdapter(playlistAdapter); + add_new.setOnClickListener(view -> { - final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AllPlaylistsActivity.this); LayoutInflater inflater1 = getLayoutInflater(); View dialogView = inflater1.inflate(R.layout.add_playlist, new LinearLayout(AllPlaylistsActivity.this), false); @@ -131,72 +129,51 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { if (display_name.getText() != null && display_name.getText().toString().trim().length() > 0) { - - Playlist playlist = new Playlist(); - playlist.setDisplayName(display_name.getText().toString().trim()); + PlaylistElement playlistElement = new PlaylistElement(); + playlistElement.setDisplayName(display_name.getText().toString().trim()); if (description.getText() != null && description.getText().toString().trim().length() > 0) { - playlist.setDescription(description.getText().toString().trim()); - } - String idChannel = null; - if (channelToSend != null) { - Map.Entry channelM = channelToSend.entrySet().iterator().next(); - idChannel = channelM.getValue(); - if (idChannel.length() > 0) - playlist.setVideoChannelId(idChannel); + playlistElement.setDescription(description.getText().toString().trim()); } + playlistElement.setVideoChannelId(idChannel); + String idPrivacy; + String label; Map.Entry privacyM = privacyToSend.entrySet().iterator().next(); - String label = privacyM.getValue(); - String idPrivacy = String.valueOf(privacyM.getKey()); - if (label.equals("Public") && (playlist.getVideoChannelId() == null || playlist.getVideoChannelId().equals(""))) { + idPrivacy = String.valueOf(privacyM.getKey()); + label = privacyM.getValue(); + if ((label.equals("Public") && (playlistElement.getVideoChannelId() == null || playlistElement.getVideoChannelId().equals("")))) { Toasty.error(AllPlaylistsActivity.this, getString(R.string.error_channel_mandatory), Toast.LENGTH_LONG).show(); } else { if (privacyToSend != null) { - playlist.setPrivacy(privacyToSend); + playlistElement.setPrivacy(idPrivacy); } - //new ManagePlaylistsAsyncTask(context, ManagePlaylistsAsyncTask.action.CREATE_PLAYLIST, playlist, null, null, DisplayPlaylistsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - UploadNotificationConfig uploadConfig = new UploadNotificationConfig(); - uploadConfig.getCompleted().autoClear = true; - try { - String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); - new MultipartUploadRequest(AllPlaylistsActivity.this, "https://" + Helper.getLiveInstance(AllPlaylistsActivity.this) + "/api/v1/video-playlists/") - //.addFileToUpload(uri.toString().replace("file://",""), "videofile") - .addHeader("Authorization", "Bearer " + token) - .setNotificationConfig(uploadConfig) - // .addParameter("name", filename) - .addParameter("videoChannelId", idChannel) - .addParameter("privacy", idPrivacy) - .addParameter("displayName", playlist.getDisplayName()) - .addParameter("description", playlist.getDescription()) - .setMaxRetries(1) - .setDelegate(new UploadStatusDelegate() { - @Override - public void onProgress(Context context, UploadInfo uploadInfo) { - // your code here - } - - @Override - public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, - Exception exception) { - // your code here - } - - @Override - public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) { - asyncTask = new ManagePlaylistsAsyncTask(AllPlaylistsActivity.this, ManagePlaylistsAsyncTask.action.GET_PLAYLIST, null, null, null, AllPlaylistsActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - @Override - public void onCancelled(Context context, UploadInfo uploadInfo) { - // your code here - } - }) - .startUpload(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - + new Thread(() -> { + try { + String playlistId = new PeertubeAPI(AllPlaylistsActivity.this).createPlaylist(playlistElement); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + Playlist playlist = new Playlist(); + playlist.setId(playlistId); + playlist.setDescription(playlistElement.getDescription()); + playlist.setDisplayName(playlistElement.getDisplayName()); + playlist.setPrivacy(privacyToSend); + playlists.add(playlist); + playlistAdapter.notifyDataSetChanged(); + }; + mainHandler.post(myRunnable); + } catch (HttpsConnection.HttpsConnectionException e) { + e.printStackTrace(); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + if (e.getMessage() != null) { + Toasty.error(AllPlaylistsActivity.this, e.getMessage(), Toast.LENGTH_LONG).show(); + } else { + Toasty.error(AllPlaylistsActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + } + }; + mainHandler.post(myRunnable); + } + }).start(); dialog.dismiss(); - add_new.setEnabled(false); } } else { Toasty.error(AllPlaylistsActivity.this, getString(R.string.error_display_name), Toast.LENGTH_LONG).show(); @@ -241,7 +218,6 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis @Override public void onActionDone(ManagePlaylistsAsyncTask.action actionType, APIResponse apiResponse, int statusCode) { mainLoader.setVisibility(View.GONE); - add_new.setEnabled(true); if (apiResponse.getError() != null) { Toasty.error(AllPlaylistsActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); return; @@ -249,11 +225,8 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis if (actionType == ManagePlaylistsAsyncTask.action.GET_PLAYLIST) { if (apiResponse.getPlaylists() != null && apiResponse.getPlaylists().size() > 0) { - List playlists = new ArrayList<>(); - ListView lv_playlist = findViewById(R.id.lv_playlist); - PlaylistAdapter playlistAdapter = new PlaylistAdapter(AllPlaylistsActivity.this, playlists, textviewNoAction); playlists.addAll(apiResponse.getPlaylists()); - lv_playlist.setAdapter(playlistAdapter); + playlistAdapter.notifyDataSetChanged(); textviewNoAction.setVisibility(View.GONE); } else { textviewNoAction.setVisibility(View.VISIBLE); @@ -288,17 +261,14 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis String[] channelId = new String[accounts.size() + 1]; int i = 1; channelName[0] = ""; - channelId[0] = ""; - channels = new HashMap<>(); + channelId[0] = "null"; + for (Account account : accounts) { - channels.put(account.getUsername(), account.getId()); channelName[i] = account.getUsername(); channelId[i] = account.getId(); i++; } - channelToSend = new HashMap<>(); - channelToSend.put(channelName[0], channelId[0]); ArrayAdapter adapterChannel = new ArrayAdapter<>(AllPlaylistsActivity.this, android.R.layout.simple_spinner_dropdown_item, channelName); set_upload_channel.setAdapter(adapterChannel); @@ -358,19 +328,7 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis set_upload_channel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { - LinkedHashMap channelsCheck = new LinkedHashMap<>(channels); - Iterator> it = channelsCheck.entrySet().iterator(); - int i = 0; - while (it.hasNext()) { - Map.Entry pair = it.next(); - if (i == position) { - channelToSend = new HashMap<>(); - channelToSend.put(pair.getKey(), pair.getValue()); - break; - } - it.remove(); - i++; - } + idChannel = channelId[position]; } @Override diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/HttpsConnection.java b/app/src/main/java/app/fedilab/fedilabtube/client/HttpsConnection.java index 8209075..81465fb 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/HttpsConnection.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/HttpsConnection.java @@ -61,6 +61,7 @@ import app.fedilab.fedilabtube.helper.FileNameCleaner; import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.interfaces.OnDownloadInterface; + @SuppressWarnings("unused") public class HttpsConnection { @@ -158,10 +159,8 @@ public class HttpsConnection { httpsURLConnection.setUseCaches(true); httpsURLConnection.setDefaultUseCaches(true); httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); - if (token != null && !token.startsWith("Basic ")) + if (token != null) httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - else if (token != null && token.startsWith("Basic ")) - httpsURLConnection.setRequestProperty("Authorization", token); httpsURLConnection.setRequestMethod("GET"); String response; if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { @@ -243,6 +242,87 @@ public class HttpsConnection { return response; } + public String postBoundary(String urlConnection, int timeout, LinkedHashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { + URL url = new URL(urlConnection); + + String boundary = "----TubeLabBoundary" + System.currentTimeMillis(); + if (proxy != null) + httpsURLConnection = (HttpsURLConnection) url.openConnection(proxy); + else + httpsURLConnection = (HttpsURLConnection) url.openConnection(); + httpsURLConnection.setConnectTimeout(timeout * 1000); + httpsURLConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + httpsURLConnection.setDoOutput(true); + httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); + if (token != null) + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); + + StringBuilder postData = new StringBuilder(); + if (paramaters != null) { + Iterator> it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = it.next(); + postData = addFormField(postData,pair.getKey(), pair.getValue(), boundary); + it.remove(); + } + postData.append("--").append(boundary).append("--"); + } + byte[] postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8); + httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + OutputStream outputStream = httpsURLConnection.getOutputStream(); + outputStream.write(postDataBytes); + + String response; + if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + response = converToString(httpsURLConnection.getInputStream()); + } else { + String error = null; + if (httpsURLConnection.getErrorStream() != null) { + InputStream stream = httpsURLConnection.getErrorStream(); + if (stream == null) { + stream = httpsURLConnection.getInputStream(); + } + try (Scanner scanner = new Scanner(stream)) { + scanner.useDelimiter("\\Z"); + if (scanner.hasNext()) { + error = scanner.next(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + int responseCode = httpsURLConnection.getResponseCode(); + try { + httpsURLConnection.getInputStream().close(); + } catch (Exception ignored) { + } + throw new HttpsConnectionException(responseCode, error); + } + getSinceMaxId(); + httpsURLConnection.getInputStream().close(); + return response; + } + private static final String LINE_FEED = "\r\n"; + /** + * Adds a form field to the request + *@param writer StringBuilder + * @param name field name + * @param value field value + */ + private StringBuilder addFormField(StringBuilder writer, String name, String value, String boundary) { + if( writer != null) { + writer.append("--").append(boundary).append(LINE_FEED); + writer.append("Content-Disposition: form-data; name=\"").append(name).append("\"") + .append(LINE_FEED); + writer.append("Content-Type: text/plain; charset=").append(StandardCharsets.UTF_8).append( + LINE_FEED); + writer.append(LINE_FEED); + writer.append(value).append(LINE_FEED); + } + return writer; + } + public String post(String urlConnection, int timeout, HashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { URL url = new URL(urlConnection); @@ -271,10 +351,8 @@ public class HttpsConnection { httpsURLConnection.setDoOutput(true); httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); httpsURLConnection.setRequestMethod("POST"); - if (token != null && !token.startsWith("Basic ")) + if (token != null) httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - else if (token != null && token.startsWith("Basic ")) - httpsURLConnection.setRequestProperty("Authorization", token); httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); @@ -495,10 +573,8 @@ public class HttpsConnection { httpsURLConnection.setConnectTimeout(timeout * 1000); httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); httpsURLConnection.setRequestMethod("PATCH"); - if (token != null && !token.startsWith("Basic ")) + if (token != null) httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - else if (token != null && token.startsWith("Basic ")) - httpsURLConnection.setRequestProperty("Authorization", token); httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); httpsURLConnection.setDoOutput(true); @@ -543,7 +619,6 @@ public class HttpsConnection { } httpsURLConnection.getInputStream().close(); return response; - } public String put(String urlConnection, int timeout, HashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { @@ -573,10 +648,8 @@ public class HttpsConnection { httpsURLConnection = (HttpsURLConnection) url.openConnection(); httpsURLConnection.setConnectTimeout(timeout * 1000); httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); - if (token != null && !token.startsWith("Basic ")) + if (token != null) httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - else if (token != null && token.startsWith("Basic ")) - httpsURLConnection.setRequestProperty("Authorization", token); httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); httpsURLConnection.setRequestMethod("PUT"); @@ -643,10 +716,8 @@ public class HttpsConnection { else httpsURLConnection = (HttpsURLConnection) url.openConnection(); httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); - if (token != null && !token.startsWith("Basic ")) + if (token != null) httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - else if (token != null && token.startsWith("Basic ")) - httpsURLConnection.setRequestProperty("Authorization", token); httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); httpsURLConnection.setRequestMethod("DELETE"); httpsURLConnection.setConnectTimeout(timeout * 1000); diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java index 896e6d6..a3ace32 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java @@ -874,9 +874,8 @@ public class PeertubeAPI { * Delete a Channel * * @param channelId String, the channel id - * @return int */ - public int deleteChannel(String channelId) throws HttpsConnection.HttpsConnectionException { + public void deleteChannel(String channelId) throws HttpsConnection.HttpsConnectionException { try { HttpsConnection httpsConnection = new HttpsConnection(context); httpsConnection.delete(getAbsoluteUrl(String.format("/video-channels/%s", channelId)), 60, null, prefKeyOauthTokenT); @@ -884,7 +883,6 @@ public class PeertubeAPI { } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { e.printStackTrace(); } - return actionCode; } @@ -922,6 +920,7 @@ public class PeertubeAPI { * @param accountId String account fetched * @return Account entity */ + @SuppressWarnings("unused") public Account getAccount(String accountId) { account = new Account(); @@ -1712,21 +1711,22 @@ public class PeertubeAPI { * Create a Playlist * * @param playlistElement PlaylistElement, the playlist elements - * @return int */ - public int createPlaylist(PlaylistElement playlistElement) throws HttpsConnection.HttpsConnectionException { + public String createPlaylist(PlaylistElement playlistElement) throws HttpsConnection.HttpsConnectionException { + String playlistId = "-1"; try { HttpsConnection httpsConnection = new HttpsConnection(context); - HashMap params = new HashMap<>(); - params.put("videoChannelId", playlistElement.getVideoChannelId()); - params.put("privacy", playlistElement.getPrivacy()); + LinkedHashMap params = new LinkedHashMap<>(); params.put("displayName", playlistElement.getDisplayName()); - httpsConnection.post(getAbsoluteUrl("/video-playlists/"), 60, params, prefKeyOauthTokenT); - actionCode = httpsConnection.getActionCode(); - } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { + params.put("privacy", playlistElement.getPrivacy()); + params.put("videoChannelId", playlistElement.getVideoChannelId()); + params.put("description", playlistElement.getDescription()); + String response = httpsConnection.postBoundary(getAbsoluteUrl("/video-playlists/"), 60, params, prefKeyOauthTokenT); + playlistId = new JSONObject(response).getJSONObject("videoPlaylist").getString("id"); + } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } - return actionCode; + return playlistId; }