|
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