mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-12-01 12:31:45 +00:00
Display transcript text and follow along the audio (#7103)
This commit is contained in:
@ -13,9 +13,11 @@ dependencies {
|
||||
implementation project(':net:common')
|
||||
implementation project(':parser:media')
|
||||
implementation project(':parser:feed')
|
||||
implementation project(':parser:transcript')
|
||||
implementation project(':storage:database')
|
||||
|
||||
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
|
||||
implementation "commons-io:commons-io:$commonsioVersion"
|
||||
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||
}
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
package de.danoeh.antennapod.ui.chapters;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.net.common.AntennapodHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
public class PodcastIndexTranscriptUtils {
|
||||
|
||||
private static final String TAG = "PodcastIndexTranscript";
|
||||
|
||||
public static String loadTranscriptFromUrl(String type, String url, boolean forceRefresh) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
Response response = null;
|
||||
try {
|
||||
Log.d(TAG, "Downloading transcript URL " + url.toString());
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
response = AntennapodHttpClient.getHttpClient().newCall(request).execute();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
str.append(response.body().string());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public static void storeTranscript(FeedMedia media, String transcript) {
|
||||
File transcriptFile = new File(media.getTranscriptFileUrl());
|
||||
FileOutputStream ostream = null;
|
||||
try {
|
||||
if (!transcriptFile.exists() && transcriptFile.createNewFile()) {
|
||||
ostream = new FileOutputStream(transcriptFile);
|
||||
ostream.write(transcript.getBytes(Charset.forName("UTF-8")));
|
||||
ostream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(ostream);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
ui/common/src/main/res/drawable/transcript.xml
Normal file
9
ui/common/src/main/res/drawable/transcript.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="?attr/action_icon_color"
|
||||
android:pathData="M240,640L560,640L560,560L240,560L240,640ZM640,640L720,640L720,560L640,560L640,640ZM240,480L320,480L320,400L240,400L240,480ZM400,480L720,480L720,400L400,400L400,480ZM160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,240Q800,240 800,240Q800,240 800,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720ZM160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L160,720Z"/>
|
||||
</vector>
|
||||
@ -258,6 +258,10 @@
|
||||
<item quantity="other">%d episodes removed from inbox.</item>
|
||||
</plurals>
|
||||
<string name="add_to_favorite_label">Add to favorites</string>
|
||||
<string name="show_transcript">Show transcript</string>
|
||||
<string name="transcript">Transcript</string>
|
||||
<string name="transcript_follow">Follow audio</string>
|
||||
<string name="no_transcript_label">No transcript</string>
|
||||
<string name="remove_from_favorite_label">Remove from favorites</string>
|
||||
<string name="visit_website_label">Visit website</string>
|
||||
<string name="skip_episode_label">Skip episode</string>
|
||||
|
||||
20
ui/transcript/build.gradle
Normal file
20
ui/transcript/build.gradle
Normal file
@ -0,0 +1,20 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
}
|
||||
apply from: "../../common.gradle"
|
||||
apply from: "../../playFlavor.gradle"
|
||||
|
||||
android {
|
||||
namespace "de.danoeh.antennapod.ui.transcript"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':model')
|
||||
implementation project(':net:common')
|
||||
implementation project(':parser:media')
|
||||
implementation project(':parser:transcript')
|
||||
|
||||
implementation "commons-io:commons-io:$commonsioVersion"
|
||||
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
package de.danoeh.antennapod.ui.transcript;
|
||||
|
||||
import android.util.Log;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.nio.charset.Charset;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.net.common.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.model.feed.Transcript;
|
||||
import de.danoeh.antennapod.parser.transcript.TranscriptParser;
|
||||
import okhttp3.CacheControl;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class TranscriptUtils {
|
||||
private static final String TAG = "Transcript";
|
||||
|
||||
public static String loadTranscriptFromUrl(String url, boolean forceRefresh) throws InterruptedIOException {
|
||||
if (forceRefresh) {
|
||||
return loadTranscriptFromUrl(url, CacheControl.FORCE_NETWORK);
|
||||
}
|
||||
String str = loadTranscriptFromUrl(url, CacheControl.FORCE_CACHE);
|
||||
if (str == null || str.length() <= 1) {
|
||||
// Some publishers use one dummy transcript before actual transcript are available
|
||||
return loadTranscriptFromUrl(url, CacheControl.FORCE_NETWORK);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private static String loadTranscriptFromUrl(String url, CacheControl cacheControl) throws InterruptedIOException {
|
||||
StringBuilder str = new StringBuilder();
|
||||
Response response = null;
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Downloading transcript URL " + url);
|
||||
Request request = new Request.Builder().url(url).cacheControl(cacheControl).build();
|
||||
response = AntennapodHttpClient.getHttpClient().newCall(request).execute();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
Log.d(TAG, "Done Downloading transcript URL " + url);
|
||||
str.append(response.body().string());
|
||||
} else {
|
||||
Log.d(TAG, "Error Downloading transcript URL " + url + ": " + response.message());
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
Log.d(TAG, "InterruptedIOException while downloading transcript URL " + url);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public static Transcript loadTranscript(FeedMedia media, Boolean forceRefresh) throws InterruptedIOException {
|
||||
String transcriptType = media.getItem().getTranscriptType();
|
||||
|
||||
if (!forceRefresh && media.getItem().getTranscript() != null) {
|
||||
return media.getTranscript();
|
||||
}
|
||||
|
||||
if (!forceRefresh && media.getTranscriptFileUrl() != null) {
|
||||
File transcriptFile = new File(media.getTranscriptFileUrl());
|
||||
try {
|
||||
if (transcriptFile.exists()) {
|
||||
String t = FileUtils.readFileToString(transcriptFile, (String) null);
|
||||
if (StringUtils.isNotEmpty(t)) {
|
||||
media.setTranscript(TranscriptParser.parse(t, transcriptType));
|
||||
return media.getTranscript();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String transcriptUrl = media.getItem().getTranscriptUrl();
|
||||
String t = TranscriptUtils.loadTranscriptFromUrl(transcriptUrl, forceRefresh);
|
||||
if (StringUtils.isNotEmpty(t)) {
|
||||
return TranscriptParser.parse(t, transcriptType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void storeTranscript(FeedMedia media, String transcript) {
|
||||
File transcriptFile = new File(media.getTranscriptFileUrl());
|
||||
FileOutputStream ostream = null;
|
||||
try {
|
||||
if (transcriptFile.exists() && !transcriptFile.delete()) {
|
||||
Log.e(TAG, "Failed to delete existing transcript file " + transcriptFile.getAbsolutePath());
|
||||
}
|
||||
if (transcriptFile.createNewFile()) {
|
||||
ostream = new FileOutputStream(transcriptFile);
|
||||
ostream.write(transcript.getBytes(Charset.forName("UTF-8")));
|
||||
ostream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(ostream);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user