|
20 | 20 |
|
21 | 21 | package org.schabi.newpipe.extractor.services.youtube.extractors;
|
22 | 22 |
|
23 |
| -import static org.schabi.newpipe.extractor.localization.TimeAgoPatternsManager.getTimeAgoParserFor; |
24 | 23 | import static org.schabi.newpipe.extractor.services.youtube.ItagItem.APPROX_DURATION_MS_UNKNOWN;
|
25 | 24 | import static org.schabi.newpipe.extractor.services.youtube.ItagItem.CONTENT_LENGTH_UNKNOWN;
|
26 | 25 | import static org.schabi.newpipe.extractor.services.youtube.YoutubeDescriptionHelper.attributedDescriptionToHtml;
|
|
60 | 59 | import org.schabi.newpipe.extractor.localization.DateWrapper;
|
61 | 60 | import org.schabi.newpipe.extractor.localization.Localization;
|
62 | 61 | import org.schabi.newpipe.extractor.localization.TimeAgoParser;
|
| 62 | +import org.schabi.newpipe.extractor.localization.TimeAgoPatternsManager; |
63 | 63 | import org.schabi.newpipe.extractor.services.youtube.ItagItem;
|
64 | 64 | import org.schabi.newpipe.extractor.services.youtube.PoTokenProvider;
|
65 | 65 | import org.schabi.newpipe.extractor.services.youtube.PoTokenResult;
|
|
104 | 104 | import javax.annotation.Nullable;
|
105 | 105 |
|
106 | 106 | public class YoutubeStreamExtractor extends StreamExtractor {
|
| 107 | + private static final String PREMIERED = "Premiered "; |
| 108 | + private static final String PREMIERED_ON = "Premiered on "; |
107 | 109 |
|
108 | 110 | @Nullable
|
109 | 111 | private static PoTokenProvider poTokenProvider;
|
@@ -172,70 +174,71 @@ public String getName() throws ParsingException {
|
172 | 174 | @Nullable
|
173 | 175 | @Override
|
174 | 176 | public String getTextualUploadDate() throws ParsingException {
|
175 |
| - final var uploadDate = getUploadDate(); |
176 |
| - if (uploadDate == null) { |
177 |
| - return null; |
178 |
| - } |
179 |
| - return LocalDate.ofInstant(uploadDate.getInstant(), ZoneId.systemDefault()).toString(); |
180 |
| - } |
181 |
| - |
182 |
| - @Override |
183 |
| - public DateWrapper getUploadDate() throws ParsingException { |
184 | 177 | final String dateStr = playerMicroFormatRenderer.getString("uploadDate",
|
185 | 178 | playerMicroFormatRenderer.getString("publishDate", ""));
|
186 | 179 | if (!dateStr.isEmpty()) {
|
187 |
| - return new DateWrapper(OffsetDateTime.parse(dateStr)); |
| 180 | + return dateStr; |
188 | 181 | }
|
189 | 182 |
|
190 | 183 | final var liveDetails = playerMicroFormatRenderer.getObject("liveBroadcastDetails");
|
191 | 184 | final String timestamp = liveDetails.getString("endTimestamp", // an ended live stream
|
192 | 185 | liveDetails.getString("startTimestamp", "")); // a running live stream
|
193 | 186 |
|
194 | 187 | if (!timestamp.isEmpty()) {
|
195 |
| - return new DateWrapper(OffsetDateTime.parse(timestamp)); |
| 188 | + return timestamp; |
196 | 189 | } else if (getStreamType() == StreamType.LIVE_STREAM) {
|
197 | 190 | // this should never be reached, but a live stream without upload date is valid
|
198 | 191 | return null;
|
199 | 192 | }
|
200 | 193 |
|
201 | 194 | final var textObject = getVideoPrimaryInfoRenderer().getObject("dateText");
|
202 |
| - return Optional.ofNullable(getTextFromObject(textObject)) |
203 |
| - .flatMap(rendererDateText -> { |
204 |
| - final Optional<LocalDate> dateOptional; |
| 195 | + final String rendererDateText = getTextFromObject(textObject); |
| 196 | + if (rendererDateText == null) { |
| 197 | + return null; |
| 198 | + } else if (rendererDateText.startsWith(PREMIERED_ON)) { // Premiered on 21 Feb 2020 |
| 199 | + return rendererDateText.substring(PREMIERED_ON.length()); |
| 200 | + } else if (rendererDateText.startsWith(PREMIERED)) { |
| 201 | + // Premiered 20 hours ago / Premiered Feb 21, 2020 |
| 202 | + return rendererDateText.substring(PREMIERED.length()); |
| 203 | + } else { |
| 204 | + return rendererDateText; |
| 205 | + } |
| 206 | + } |
205 | 207 |
|
206 |
| - if (rendererDateText.startsWith("Premiered")) { |
207 |
| - final String time = rendererDateText.substring(13); |
| 208 | + @Override |
| 209 | + public DateWrapper getUploadDate() throws ParsingException { |
| 210 | + final String dateText = getTextualUploadDate(); |
| 211 | + if (dateText == null) { |
| 212 | + return null; |
| 213 | + } |
208 | 214 |
|
209 |
| - try { // Premiered 20 hours ago |
210 |
| - final var localization = new Localization("en"); |
211 |
| - return Optional.of(getTimeAgoParserFor(localization).parse(time)); |
212 |
| - } catch (final Exception e) { |
213 |
| - } |
| 215 | + try { |
| 216 | + return new DateWrapper(OffsetDateTime.parse(dateText)); |
| 217 | + } catch (final DateTimeParseException e) { |
| 218 | + } |
214 | 219 |
|
215 |
| - // Premiered Feb 21, 2020 |
216 |
| - dateOptional = parseOptionalDate(time, "MMM dd, yyyy") |
217 |
| - // Premiered on 21 Feb 2020 |
218 |
| - .or(() -> parseOptionalDate(time, "dd MMM yyyy")); |
219 |
| - } else { |
220 |
| - // Premiered on 21 Feb 2020 |
221 |
| - dateOptional = parseOptionalDate(rendererDateText, "dd MMM yyyy"); |
222 |
| - } |
| 220 | + try { // Premiered 20 hours ago |
| 221 | + final var localization = new Localization("en"); |
| 222 | + return TimeAgoPatternsManager.getTimeAgoParserFor(localization).parse(dateText); |
| 223 | + } catch (final ParsingException e) { |
| 224 | + } |
223 | 225 |
|
224 |
| - return dateOptional.map(date -> { |
225 |
| - final var instant = date.atStartOfDay(ZoneId.systemDefault()).toInstant(); |
226 |
| - return new DateWrapper(instant, true); |
227 |
| - }); |
| 226 | + return parseOptionalDate(dateText, "MMM dd, yyyy") |
| 227 | + .or(() -> parseOptionalDate(dateText.substring(3), "dd MMM yyyy")) |
| 228 | + .map(date -> { |
| 229 | + final var instant = date.atStartOfDay(ZoneId.systemDefault()).toInstant(); |
| 230 | + return new DateWrapper(instant, true); |
228 | 231 | })
|
229 |
| - .orElseThrow(() -> new ParsingException("Could not get upload date")); |
| 232 | + .orElseThrow(() -> new ParsingException("Could not parse upload date")); |
230 | 233 | }
|
231 | 234 |
|
232 |
| - private Optional<LocalDate> parseOptionalDate(String date, String pattern) { |
| 235 | + private Optional<LocalDate> parseOptionalDate(final String date, final String pattern) { |
233 | 236 | try {
|
234 |
| - // TODO: this parses English formatted dates only, we need a better approach to |
235 |
| - // parse the textual date |
| 237 | + // TODO: this parses English formatted dates only, we need a better approach to parse |
| 238 | + // the textual date |
236 | 239 | final var formatter = DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH);
|
237 | 240 | return Optional.of(LocalDate.parse(date, formatter));
|
238 |
| - } catch (DateTimeParseException e) { |
| 241 | + } catch (final DateTimeParseException e) { |
239 | 242 | return Optional.empty();
|
240 | 243 | }
|
241 | 244 | }
|
|
0 commit comments