diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeSubscriptionExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeSubscriptionExtractor.java index be0885326..aafb1cd18 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeSubscriptionExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeSubscriptionExtractor.java @@ -10,17 +10,22 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeService; import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor; import org.schabi.newpipe.extractor.subscription.SubscriptionItem; +import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; import javax.annotation.Nonnull; import static org.schabi.newpipe.extractor.subscription.SubscriptionExtractor.ContentSource.INPUT_STREAM; /** - * Extract subscriptions from a Google takeout export (the user has to get the JSON out of the zip) + * Extract subscriptions from a Google takeout export */ public class YoutubeSubscriptionExtractor extends SubscriptionExtractor { private static final String BASE_CHANNEL_URL = "https://www.youtube.com/channel/"; @@ -37,6 +42,30 @@ public class YoutubeSubscriptionExtractor extends SubscriptionExtractor { @Override public List fromInputStream(@Nonnull final InputStream contentInputStream) throws ExtractionException { + return fromJsonInputStream(contentInputStream); + } + + @Override + public List fromInputStream(@Nonnull final InputStream contentInputStream, String contentType) + throws ExtractionException { + switch (contentType) { + case "json": + case "application/json": + return fromJsonInputStream(contentInputStream); + case "csv": + case "text/csv": + case "text/comma-separated-values": + return fromCsvInputStream(contentInputStream); + case "zip": + case "application/zip": + return fromZipInputStream(contentInputStream); + default: + throw new InvalidSourceException("Unsupported content type: " + contentType); + } + } + + public List fromJsonInputStream(@Nonnull final InputStream contentInputStream) + throws ExtractionException { final JsonArray subscriptions; try { subscriptions = JsonParser.array().from(contentInputStream); @@ -68,4 +97,109 @@ public class YoutubeSubscriptionExtractor extends SubscriptionExtractor { } return subscriptionItems; } + + public List fromZipInputStream(@Nonnull final InputStream contentInputStream) + throws ExtractionException { + final ZipInputStream zipInputStream = new ZipInputStream(contentInputStream); + + try { + ZipEntry zipEntry; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + if (zipEntry.getName().toLowerCase().endsWith(".csv")) { + try { + final List csvItems = fromCsvInputStream(zipInputStream); + + // Return it only if it has items (it exits early if it's the wrong file format) + // Otherwise try the next file + if (csvItems.size() > 0) { + return csvItems; + } + } catch (ExtractionException e) { + // Ignore error and go to next file + // (maybe log it?) + } + } + } + } catch (IOException e) { + throw new InvalidSourceException("Error reading contents of zip file", e); + } + + throw new InvalidSourceException("Unable to find a valid subscriptions.csv file (try extracting and selecting the csv file)"); + } + + public List fromCsvInputStream(@Nonnull final InputStream contentInputStream) + throws ExtractionException { + // Expected format of CSV file: + // Channel Id,Channel Url,Channel Title + // UC1JTQBa5QxZCpXrFSkMxmPw,http://www.youtube.com/channel/UC1JTQBa5QxZCpXrFSkMxmPw,Raycevick + // UCFl7yKfcRcFmIUbKeCA-SJQ,http://www.youtube.com/channel/UCFl7yKfcRcFmIUbKeCA-SJQ,Joji + // + // Notes: + // It's always 3 columns + // The first line is always a header + // Header names are different based on the locale + // Fortunately the data is always the same order no matter what locale + + int currentLine = 0; + String line = ""; + + try (BufferedReader br = new BufferedReader(new InputStreamReader(contentInputStream))) { + final List subscriptionItems = new ArrayList<>(); + + // Ignore header + currentLine = 1; + line = br.readLine(); + + while ((line = br.readLine()) != null) { + currentLine++; + + // Exit early if we've read the first few lines and we haven't added any items + // It's likely we're in the wrong file + if (currentLine > 5 && subscriptionItems.size() == 0) { + break; + } + + // First comma + int i1 = line.indexOf(","); + if (i1 == -1) { + continue; + } + + // Second comma + int i2 = line.indexOf(",", i1 + 1); + if (i2 == -1) { + continue; + } + + // Third comma or line length + int i3 = line.indexOf(",", i2 + 1); + if (i3 == -1) { + i3 = line.length(); + } + + // Channel URL from second entry + final String channelUrl = line + .substring(i1 + 1, i2) + .replace("http://", "https://"); + if (!channelUrl.startsWith(BASE_CHANNEL_URL)) { + continue; + } + + // Channel title from third entry + final String channelTitle = line.substring(i2 + 1, i3); + + final SubscriptionItem newItem = new SubscriptionItem(service.getServiceId(), channelUrl, channelTitle); + subscriptionItems.add(newItem); + } + + return subscriptionItems; + } catch (IOException e) { + if (line == null) { + line = ""; + } else if (line.length() > 10) { + line = line.substring(0, 10) + "..."; + } + throw new InvalidSourceException("Error reading CSV file, line = '" + line + "', line number = " + currentLine); + } + } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/subscription/SubscriptionExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/subscription/SubscriptionExtractor.java index 8a31b0f75..b2a2d75ef 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/subscription/SubscriptionExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/subscription/SubscriptionExtractor.java @@ -77,4 +77,15 @@ public abstract class SubscriptionExtractor { throw new UnsupportedOperationException("Service " + service.getServiceInfo().getName() + " doesn't support extracting from an InputStream"); } + + /** + * Reads and parse a list of {@link SubscriptionItem} from the given InputStream. + * + * @throws InvalidSourceException when the content read from the InputStream is invalid and can not be parsed + */ + public List fromInputStream(@Nonnull final InputStream contentInputStream, String contentType) + throws ExtractionException { + throw new UnsupportedOperationException("Service " + service.getServiceInfo().getName() + + " doesn't support extracting from an InputStream"); + } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSubscriptionExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSubscriptionExtractorTest.java index c8f87a901..e00601ac7 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSubscriptionExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeSubscriptionExtractorTest.java @@ -11,6 +11,7 @@ import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor; import org.schabi.newpipe.extractor.subscription.SubscriptionItem; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.FileInputStream; import java.util.Arrays; import java.util.List; @@ -110,4 +111,48 @@ public class YoutubeSubscriptionExtractorTest { } } } + + private static void assertSubscriptionItems(final List subscriptionItems) + throws Exception { + assertTrue(subscriptionItems.size() > 0); + + for (final SubscriptionItem item : subscriptionItems) { + assertNotNull(item.getName()); + assertNotNull(item.getUrl()); + assertTrue(urlHandler.acceptUrl(item.getUrl())); + assertEquals(ServiceList.YouTube.getServiceId(), item.getServiceId()); + } + } + + @Test + public void fromZipInputStream() throws Exception { + final List zipPaths = Arrays.asList( + "youtube_takeout_import_test_1.zip", + "youtube_takeout_import_test_2.zip" + ); + + for (final String path : zipPaths) + { + final File file = resolveTestResource(path); + final FileInputStream fileInputStream = new FileInputStream(file); + final List subscriptionItems = subscriptionExtractor.fromZipInputStream(fileInputStream); + assertSubscriptionItems(subscriptionItems); + } + } + + @Test + public void fromCsvInputStream() throws Exception { + final List csvPaths = Arrays.asList( + "youtube_takeout_import_test_1.csv", + "youtube_takeout_import_test_2.csv" + ); + + for (String path : csvPaths) + { + final File file = resolveTestResource(path); + final FileInputStream fileInputStream = new FileInputStream(file); + final List subscriptionItems = subscriptionExtractor.fromCsvInputStream(fileInputStream); + assertSubscriptionItems(subscriptionItems); + } + } } diff --git a/extractor/src/test/resources/youtube_takeout_import_test_1.csv b/extractor/src/test/resources/youtube_takeout_import_test_1.csv new file mode 100644 index 000000000..b71d9af2c --- /dev/null +++ b/extractor/src/test/resources/youtube_takeout_import_test_1.csv @@ -0,0 +1,7 @@ +Channel Id,Channel Url,Channel Title +UC1JTQBa5QxZCpXrFSkMxmPw,http://www.youtube.com/channel/UC1JTQBa5QxZCpXrFSkMxmPw,Raycevick +UC3ltptWa0xfrDweghW94Acg,http://www.youtube.com/channel/UC3ltptWa0xfrDweghW94Acg,Karl Jobst +UC9PBzalIcEQCsiIkq36PyUA,http://www.youtube.com/channel/UC9PBzalIcEQCsiIkq36PyUA,Digital Foundry +UCU64AfivgQUOPuIJ8N5YaCA,http://www.youtube.com/channel/UCU64AfivgQUOPuIJ8N5YaCA,EventStatus +UCsvn_Po0SmunchJYOWpOxMg,http://www.youtube.com/channel/UCsvn_Po0SmunchJYOWpOxMg,videogamedunkey + diff --git a/extractor/src/test/resources/youtube_takeout_import_test_1.zip b/extractor/src/test/resources/youtube_takeout_import_test_1.zip new file mode 100644 index 000000000..69a0e7b3c Binary files /dev/null and b/extractor/src/test/resources/youtube_takeout_import_test_1.zip differ diff --git a/extractor/src/test/resources/youtube_takeout_import_test_2.csv b/extractor/src/test/resources/youtube_takeout_import_test_2.csv new file mode 100644 index 000000000..a718ee824 --- /dev/null +++ b/extractor/src/test/resources/youtube_takeout_import_test_2.csv @@ -0,0 +1,174 @@ +ID del canal,URL del canal,Título del canal +UC-UcKEWOSpz0AfY33TrYw3g,http://www.youtube.com/channel/UC-UcKEWOSpz0AfY33TrYw3g,Nekojitablog +UC-lHJZR3Gqxm24_Vd_AJ5Yw,http://www.youtube.com/channel/UC-lHJZR3Gqxm24_Vd_AJ5Yw,PewDiePie +UC-uZVnE4p_52zXbH34S4pcA,http://www.youtube.com/channel/UC-uZVnE4p_52zXbH34S4pcA,CRD Сreative +UC08if0oBaJcpxQQaa7wJZ0g,http://www.youtube.com/channel/UC08if0oBaJcpxQQaa7wJZ0g,Gerry Studios +UC0B7gD411SJ4DkQYnSwFAcQ,http://www.youtube.com/channel/UC0B7gD411SJ4DkQYnSwFAcQ,potasticp +UC0KfjyvabuE2J-RBC6ko2Lw,http://www.youtube.com/channel/UC0KfjyvabuE2J-RBC6ko2Lw,Mac Address +UC0pHpxSt_4gd63WylQL0cVQ,http://www.youtube.com/channel/UC0pHpxSt_4gd63WylQL0cVQ,Pipepino +UC1_aBBbg4vzI_Y8QAolPcCA,http://www.youtube.com/channel/UC1_aBBbg4vzI_Y8QAolPcCA,KillerCreeper55 - Minecraft +UC1n_PfsVqxllCcnMPlxBIjw,http://www.youtube.com/channel/UC1n_PfsVqxllCcnMPlxBIjw,Wilbur Soot +UC21XRv2sCF43MKL1WKHAP9w,http://www.youtube.com/channel/UC21XRv2sCF43MKL1WKHAP9w,We Skeem +UC29GGV1kYu1MlpS6VRhIRZw,http://www.youtube.com/channel/UC29GGV1kYu1MlpS6VRhIRZw,ZellenDust +UC29RfHuFFanQjXSX7XaFHuw,http://www.youtube.com/channel/UC29RfHuFFanQjXSX7XaFHuw,Julieta Appoloni +UC2sOV9xZJ8m21bi7WUmTBIw,http://www.youtube.com/channel/UC2sOV9xZJ8m21bi7WUmTBIw,Fzst +UC34DnjIkx6EJLk6pwlDoGTQ,http://www.youtube.com/channel/UC34DnjIkx6EJLk6pwlDoGTQ,EsVandal +UC36xmz34q02JYaZYKrMwXng,http://www.youtube.com/channel/UC36xmz34q02JYaZYKrMwXng,Nate Gentile +UC3jSNmKWYA04R47fDcc1ImA,http://www.youtube.com/channel/UC3jSNmKWYA04R47fDcc1ImA,InfinitelyGalactic +UC3zd273Sh1s2HPdGAmITZxQ,http://www.youtube.com/channel/UC3zd273Sh1s2HPdGAmITZxQ,IbraH +UC4jKcxlBvTZpkPyatMMfgpQ,http://www.youtube.com/channel/UC4jKcxlBvTZpkPyatMMfgpQ,Anna Aerien +UC5SCKE-sVHhdS57hNhzkKTA,http://www.youtube.com/channel/UC5SCKE-sVHhdS57hNhzkKTA,COSMIC KID +UC5UAwBUum7CPN5buc-_N1Fw,http://www.youtube.com/channel/UC5UAwBUum7CPN5buc-_N1Fw,The Linux Experiment +UC6UjsfZ7PNcCF51JAgh5EIQ,http://www.youtube.com/channel/UC6UjsfZ7PNcCF51JAgh5EIQ,Tkeio ! +UC71kKpUN9OQMl_HivC19A_g,http://www.youtube.com/channel/UC71kKpUN9OQMl_HivC19A_g,Luh +UC7AHXsGbhbGwFhk8FcLqNIQ,http://www.youtube.com/channel/UC7AHXsGbhbGwFhk8FcLqNIQ,Jake Marley +UC7Jwj9fkrf1adN4fMmTkpug,http://www.youtube.com/channel/UC7Jwj9fkrf1adN4fMmTkpug,DankPods +UC7YOGHUfC1Tb6E4pudI9STA,http://www.youtube.com/channel/UC7YOGHUfC1Tb6E4pudI9STA,Mental Outlaw +UC7qdNWFCD3lo8toe0TsaeUw,http://www.youtube.com/channel/UC7qdNWFCD3lo8toe0TsaeUw,CrisGreen ( ͡° 3 ͡°) +UC8JUloCS-XOMOi9w_JLegDw,http://www.youtube.com/channel/UC8JUloCS-XOMOi9w_JLegDw,yuganlovetacos +UC8qKhubxKNyX5A_cXz7e_vg,http://www.youtube.com/channel/UC8qKhubxKNyX5A_cXz7e_vg,Ouros +UC9_krwU8wTPCZRKaf34QnPw,http://www.youtube.com/channel/UC9_krwU8wTPCZRKaf34QnPw,Farfadox +UC9n8N8u98RVbhOTTjXpyR5A,http://www.youtube.com/channel/UC9n8N8u98RVbhOTTjXpyR5A,La Piña Kawaii +UCAZlPagsIabYqmZEz80Ov2Q,http://www.youtube.com/channel/UCAZlPagsIabYqmZEz80Ov2Q,Metrica +UCAmralsz60sfzuxucXHIuXA,http://www.youtube.com/channel/UCAmralsz60sfzuxucXHIuXA,Devil Haru Ch. +UCB18IliCiBeraa8oysaTZSQ,http://www.youtube.com/channel/UCB18IliCiBeraa8oysaTZSQ,Miraie +UCBa659QWEk1AI4Tg--mrJ2A,http://www.youtube.com/channel/UCBa659QWEk1AI4Tg--mrJ2A,Tom Scott +UCC4s-auWsFG53zpcqCMyD1Q,http://www.youtube.com/channel/UCC4s-auWsFG53zpcqCMyD1Q,yaco beltran +UCC8u8qnUYqXpjQkdqTcfoAg,http://www.youtube.com/channel/UCC8u8qnUYqXpjQkdqTcfoAg,SupraClips +UCDK9qD5DAQML-pzrtA7A4oA,http://www.youtube.com/channel/UCDK9qD5DAQML-pzrtA7A4oA,OfflineTV +UCDPv4No6VB2L5tz-ucdE66g,http://www.youtube.com/channel/UCDPv4No6VB2L5tz-ucdE66g,Denis Orlando +UCE5ZRpNnq2kJI0mza6a2w6g,http://www.youtube.com/channel/UCE5ZRpNnq2kJI0mza6a2w6g,SupraPixel X +UCEG3ulBltfrvOE8baBogJ0g,http://www.youtube.com/channel/UCEG3ulBltfrvOE8baBogJ0g,ZONE TOONS +UCEuANnOyczsSWmabtxg1kIA,http://www.youtube.com/channel/UCEuANnOyczsSWmabtxg1kIA,ivo31 YT +UCFR2oaNj02WnXkOgLH0iqOA,http://www.youtube.com/channel/UCFR2oaNj02WnXkOgLH0iqOA,Auron +UCFl7yKfcRcFmIUbKeCA-SJQ,http://www.youtube.com/channel/UCFl7yKfcRcFmIUbKeCA-SJQ,Joji +UCFz9NxZISfloIeqaTUovmrQ,http://www.youtube.com/channel/UCFz9NxZISfloIeqaTUovmrQ,Pedo Gaming +UCGntRpUdlsUG0tcvj2zIAIQ,http://www.youtube.com/channel/UCGntRpUdlsUG0tcvj2zIAIQ,FranzJ +UCGsVaz3QTFdspLqt79jIuPA,http://www.youtube.com/channel/UCGsVaz3QTFdspLqt79jIuPA,Guinxu +UCGwu0nbY2wSkW8N-cghnLpA,http://www.youtube.com/channel/UCGwu0nbY2wSkW8N-cghnLpA,Jaiden Animations +UCHMo5_1W1bRHapGOTM5ieIg,http://www.youtube.com/channel/UCHMo5_1W1bRHapGOTM5ieIg,Conterstine +UCHXJ0dhS3NpTBFg7lR_5w8Q,http://www.youtube.com/channel/UCHXJ0dhS3NpTBFg7lR_5w8Q,Also Fitz +UCHZ986wm_sJT6wntdDTIIcw,http://www.youtube.com/channel/UCHZ986wm_sJT6wntdDTIIcw,FitMC +UCI4i5O3BPZZWbbX4J345crA,http://www.youtube.com/channel/UCI4i5O3BPZZWbbX4J345crA,Mery Soldier +UCIbTKu0fPqqCOIW-BNeOqdA,http://www.youtube.com/channel/UCIbTKu0fPqqCOIW-BNeOqdA,Shadoune666 +UCJdoOeD2N8sM_LEREHG6kYQ,http://www.youtube.com/channel/UCJdoOeD2N8sM_LEREHG6kYQ,omotea +UCJxv80y78XTCUqfiplmDyRw,http://www.youtube.com/channel/UCJxv80y78XTCUqfiplmDyRw,Tri-line +UCK1W7jhV8g0JuAJbaZYyehA,http://www.youtube.com/channel/UCK1W7jhV8g0JuAJbaZYyehA,Dylantero Sin Imaginación +UCKHR-onQ7E0vyrEWgxiRljQ,http://www.youtube.com/channel/UCKHR-onQ7E0vyrEWgxiRljQ,kingani +UCM66PelO5iYSanEGWowaCVA,http://www.youtube.com/channel/UCM66PelO5iYSanEGWowaCVA,Gissely +UCNJL4PCMVJVNcYWPSH009rg,http://www.youtube.com/channel/UCNJL4PCMVJVNcYWPSH009rg,NightcoreChase +UCNYW2vfGrUE6R5mIJYzkRyQ,http://www.youtube.com/channel/UCNYW2vfGrUE6R5mIJYzkRyQ,DrossRotzank +UCOGLfpN-nkRjPZz2w1dTuew,http://www.youtube.com/channel/UCOGLfpN-nkRjPZz2w1dTuew,TGet! +UCP61sZSPUlFsDdCm72Z6b-Q,http://www.youtube.com/channel/UCP61sZSPUlFsDdCm72Z6b-Q,Atrial +UCPbGiUt4Yu8EsaFM-KAmgjg,http://www.youtube.com/channel/UCPbGiUt4Yu8EsaFM-KAmgjg,Grizzy +UCPr3T20IPZ03gU9gZ2BwM5g,http://www.youtube.com/channel/UCPr3T20IPZ03gU9gZ2BwM5g,The Click +UCQ-JZLA6Zbwffkl4VGdeCYw,http://www.youtube.com/channel/UCQ-JZLA6Zbwffkl4VGdeCYw,Matias Candia +UCQCnMFr8uHBaMTaNBhych_A,http://www.youtube.com/channel/UCQCnMFr8uHBaMTaNBhych_A,Mini Ladd +UCQDhxkSxZA6lxdeXE19aoRA,http://www.youtube.com/channel/UCQDhxkSxZA6lxdeXE19aoRA,Hugh Jeffreys +UCS-WzPVpAAli-1IfEG2lN8A,http://www.youtube.com/channel/UCS-WzPVpAAli-1IfEG2lN8A,Michael MJD +UCS3Zvg_emGJF6RNgWyXOynw,http://www.youtube.com/channel/UCS3Zvg_emGJF6RNgWyXOynw,Jake Frew +UCSa0hnM2n_yvOnecoQ2fgxA,http://www.youtube.com/channel/UCSa0hnM2n_yvOnecoQ2fgxA,Jamie Pine +UCScy7OHZSdRTCbs_KPsutcA,http://www.youtube.com/channel/UCScy7OHZSdRTCbs_KPsutcA,Landidzu +UCStaCkxg1uRCjYWsgQFu8zQ,http://www.youtube.com/channel/UCStaCkxg1uRCjYWsgQFu8zQ,MxR Doesn't Play +UCSunSIhBSrgzYzx2Yd5Rxaw,http://www.youtube.com/channel/UCSunSIhBSrgzYzx2Yd5Rxaw,Frankkaster +UCT35hFvV0j8SR3SBGJChKZQ,http://www.youtube.com/channel/UCT35hFvV0j8SR3SBGJChKZQ,Jota. +UCTA1snhmGZapRRilB6VzJGA,http://www.youtube.com/channel/UCTA1snhmGZapRRilB6VzJGA,Silithur V +UCVBkwO6Ok1De0UfNZdo7-Ag,http://www.youtube.com/channel/UCVBkwO6Ok1De0UfNZdo7-Ag,DayoScript +UCVRWkwOQIpxPOhQ9V-gL2UA,http://www.youtube.com/channel/UCVRWkwOQIpxPOhQ9V-gL2UA,SIAMES +UCVUVc506EM6TG-7wmv3i2gA,http://www.youtube.com/channel/UCVUVc506EM6TG-7wmv3i2gA,¡ KHAZOO ! +UCVls1GmFKf6WlTraIb_IaJg,http://www.youtube.com/channel/UCVls1GmFKf6WlTraIb_IaJg,DistroTube +UCVrrU-Z0cxcVIX9uq40LoqA,http://www.youtube.com/channel/UCVrrU-Z0cxcVIX9uq40LoqA,Gona89 +UCWNxXrELNgyeJgYcF3wEJ-A,http://www.youtube.com/channel/UCWNxXrELNgyeJgYcF3wEJ-A,Indiruskis Official +UCWYmWfb9O-Di7cOVUzBpRHA,http://www.youtube.com/channel/UCWYmWfb9O-Di7cOVUzBpRHA,Rubik +UCX3qiJ-Ivoke80Tklb49dDg,http://www.youtube.com/channel/UCX3qiJ-Ivoke80Tklb49dDg,Shadow! +UCX6OQ3DkcsbYNE6H8uQQuVA,http://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA,MrBeast +UCXazgXDIYyWH-yXLAkcrFxw,http://www.youtube.com/channel/UCXazgXDIYyWH-yXLAkcrFxw,elrubiusOMG +UCXdWux01giurAUf2fPjXyRQ,http://www.youtube.com/channel/UCXdWux01giurAUf2fPjXyRQ,ZellenDos - ZellenDust en version extendida (GAMEPLAYS) +UCXogpAmELid1pTAx5KxJzGw,http://www.youtube.com/channel/UCXogpAmELid1pTAx5KxJzGw,Sendates +UCXuqSBlHAE6Xw-yeJA0Tunw,http://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw,Linus Tech Tips +UCY2ekMrWhsUVHwO3J3-PCzQ,http://www.youtube.com/channel/UCY2ekMrWhsUVHwO3J3-PCzQ,steveee +UCYkKGJj-G_W2vipGnuJOrKA,http://www.youtube.com/channel/UCYkKGJj-G_W2vipGnuJOrKA,Pato Asado +UCZU_0ozD_jE_3X0txiK92rA,http://www.youtube.com/channel/UCZU_0ozD_jE_3X0txiK92rA,Rusbi +UCZX4xIxNNwf84kN9Mi4lu2A,http://www.youtube.com/channel/UCZX4xIxNNwf84kN9Mi4lu2A,HakuEXE +UCZpLsmMwIECgY5j6IsOqNwQ,http://www.youtube.com/channel/UCZpLsmMwIECgY5j6IsOqNwQ,orslok +UC_63umCUF3kuSwnhpUyhemg,http://www.youtube.com/channel/UC_63umCUF3kuSwnhpUyhemg,MxR Shorts +UC_jx6UXvRPu5g_BsSLwlMGw,http://www.youtube.com/channel/UC_jx6UXvRPu5g_BsSLwlMGw,Los Vlogs de Dross +UC_qspxIbv_iMtfg7rJfbyOg,http://www.youtube.com/channel/UC_qspxIbv_iMtfg7rJfbyOg,Japatonic LITE +UCa3DVlGH2_QhvwuWlPa6MDQ,http://www.youtube.com/channel/UCa3DVlGH2_QhvwuWlPa6MDQ,Jaime Altozano +UCa56-DbKF-j9rlgKNKt6z6w,http://www.youtube.com/channel/UCa56-DbKF-j9rlgKNKt6z6w,G1G0 +UCaHT88aobpcvRFEuy4v5Clg,http://www.youtube.com/channel/UCaHT88aobpcvRFEuy4v5Clg,Lessons in Meme Culture +UCamLstJyCa-t5gfZegxsFMw,http://www.youtube.com/channel/UCamLstJyCa-t5gfZegxsFMw,Colin and Samir +UCbvbFVlbArZWdouAqWKOVJg,http://www.youtube.com/channel/UCbvbFVlbArZWdouAqWKOVJg,Nexpo: After Hours +UCcjIvuxmWlS5IEQ0JdPV4Ng,http://www.youtube.com/channel/UCcjIvuxmWlS5IEQ0JdPV4Ng,Rubius Z +UCd3aWvyGFbNjsJV0S7G-tgw,http://www.youtube.com/channel/UCd3aWvyGFbNjsJV0S7G-tgw,Avdan +UCd4XwUn2Lure2NHHjukoCwA,http://www.youtube.com/channel/UCd4XwUn2Lure2NHHjukoCwA,Linux For Everyone +UCdBK94H6oZT2Q7l0-b0xmMg,http://www.youtube.com/channel/UCdBK94H6oZT2Q7l0-b0xmMg,ShortCircuit +UCdRx6BjmUwdP7pfGIYPRHaQ,http://www.youtube.com/channel/UCdRx6BjmUwdP7pfGIYPRHaQ,alexelcapo +UCeeFfhMcJa1kjtfZAGskOCA,http://www.youtube.com/channel/UCeeFfhMcJa1kjtfZAGskOCA,TechLinked +UCfgV8Gpt4ZkbvJFBpxpi7JA,http://www.youtube.com/channel/UCfgV8Gpt4ZkbvJFBpxpi7JA,Keisari +UCg3qsVzHeUt5_cPpcRtoaJQ,http://www.youtube.com/channel/UCg3qsVzHeUt5_cPpcRtoaJQ,圧倒的不審者の極み! +UCg6gPGh8HU2U01vaFCAsvmQ,http://www.youtube.com/channel/UCg6gPGh8HU2U01vaFCAsvmQ,Chris Titus Tech +UCgBS3WiEFJxUj4N-_xQcpPA,http://www.youtube.com/channel/UCgBS3WiEFJxUj4N-_xQcpPA,DEFI BRILATOR +UChBSlTzHKUabiXaIXd3y0rg,http://www.youtube.com/channel/UChBSlTzHKUabiXaIXd3y0rg,Furro Azul +UChFm1c5n1zlqK4-EitRPPRQ,http://www.youtube.com/channel/UChFm1c5n1zlqK4-EitRPPRQ,La red de Mario +UChRV-sCl5Fma4qm_hFpDKBQ,http://www.youtube.com/channel/UChRV-sCl5Fma4qm_hFpDKBQ,Ephemeral Rift +UCjJ_2P7-Xx9Fb7zHea9mqSw,http://www.youtube.com/channel/UCjJ_2P7-Xx9Fb7zHea9mqSw,Derpixon +UCjSEJkpGbcZhvo0lr-44X_w,http://www.youtube.com/channel/UCjSEJkpGbcZhvo0lr-44X_w,TechHut +UCjxeK73CBe_ftHp16xnABDA,http://www.youtube.com/channel/UCjxeK73CBe_ftHp16xnABDA,Dualitty +UCkPqufdW60E1z9vHfigA8QQ,http://www.youtube.com/channel/UCkPqufdW60E1z9vHfigA8QQ,Nico Paviolo +UCkPsz9QkX5rKlKiPV3ymltA,http://www.youtube.com/channel/UCkPsz9QkX5rKlKiPV3ymltA,NarkNation +UCkitABalXafr-NqceQdDXtg,http://www.youtube.com/channel/UCkitABalXafr-NqceQdDXtg,TVFilthyFrank +UCkqcbakfUZ_tRF_12AkSK9A,http://www.youtube.com/channel/UCkqcbakfUZ_tRF_12AkSK9A,Giuly Cobian +UCku1mRyxRdPxy_WuWcuGZow,http://www.youtube.com/channel/UCku1mRyxRdPxy_WuWcuGZow,Cri2Green +UCl2mFZoRqjw_ELax4Yisf6w,http://www.youtube.com/channel/UCl2mFZoRqjw_ELax4Yisf6w,Louis Rossmann +UClOTXvBhNkVce1J8gsXncAw,http://www.youtube.com/channel/UClOTXvBhNkVce1J8gsXncAw,8choPlay +UCl_VgfLer0xGmMnHiUaXIiw,http://www.youtube.com/channel/UCl_VgfLer0xGmMnHiUaXIiw,Amanda Parot +UCld68syR8Wi-GY_n4CaoJGA,http://www.youtube.com/channel/UCld68syR8Wi-GY_n4CaoJGA,Brodie Robertson +UClv_RjOAHch27mb_Yy-6zzQ,http://www.youtube.com/channel/UClv_RjOAHch27mb_Yy-6zzQ,RodSquare +UCmOiT9ZnSvLZ1XMBFjGiNmQ,http://www.youtube.com/channel/UCmOiT9ZnSvLZ1XMBFjGiNmQ,‌ +UCmS75G-98QihSusY7NfCZtw,http://www.youtube.com/channel/UCmS75G-98QihSusY7NfCZtw,Bizarrap +UCmb0LnmFYceH7toqgmUTJDA,http://www.youtube.com/channel/UCmb0LnmFYceH7toqgmUTJDA,Vandal +UCnTB8uNxND40iwvPiyzpnWw,http://www.youtube.com/channel/UCnTB8uNxND40iwvPiyzpnWw,heiakim +UCnXKG-SXe58CDCwxltHYQZg,http://www.youtube.com/channel/UCnXKG-SXe58CDCwxltHYQZg,ً +UCngOaQh68FzLqK1LqoUs0rw,http://www.youtube.com/channel/UCngOaQh68FzLqK1LqoUs0rw,NIGHTPLEASE YT +UCnq5UPLhlAEttKl8sszFmvw,http://www.youtube.com/channel/UCnq5UPLhlAEttKl8sszFmvw,Hartvigen +UCo5HJNjfdSoPWsdAHLsvSxQ,http://www.youtube.com/channel/UCo5HJNjfdSoPWsdAHLsvSxQ,ShaunTrack +UCo8bcnLyZH8tBIH9V1mLgqQ,http://www.youtube.com/channel/UCo8bcnLyZH8tBIH9V1mLgqQ,TheOdd1sOut +UCoGBPBXyq28cE4g2TaB6lRQ,http://www.youtube.com/channel/UCoGBPBXyq28cE4g2TaB6lRQ,Damian Kuc +UCocHtA1ADT6kTObipYzJoww,http://www.youtube.com/channel/UCocHtA1ADT6kTObipYzJoww,SunlessKhan +UCpFFItkfZz1qz5PpHpqzYBw,http://www.youtube.com/channel/UCpFFItkfZz1qz5PpHpqzYBw,Nexpo +UCpUcgGF1nS6rp6-L9OWfbTw,http://www.youtube.com/channel/UCpUcgGF1nS6rp6-L9OWfbTw,woofnion +UCppX-xsYa-PTE09GAoFCo3Q,http://www.youtube.com/channel/UCppX-xsYa-PTE09GAoFCo3Q,MrCarlosnoob +UCq6VFHwMzcMXbuKyG7SQYIg,http://www.youtube.com/channel/UCq6VFHwMzcMXbuKyG7SQYIg,penguinz0 +UCq6aw03lNILzV96UvEAASfQ,http://www.youtube.com/channel/UCq6aw03lNILzV96UvEAASfQ,bill wurtz +UCqW41JX8pX9yJxfQ9cEXUEQ,http://www.youtube.com/channel/UCqW41JX8pX9yJxfQ9cEXUEQ,Atto Usagi +UCqbkm47qBxDj-P3lI9voIAw,http://www.youtube.com/channel/UCqbkm47qBxDj-P3lI9voIAw,danooct1 +UCrK0KR016cpACKJ5jyy0MwQ,http://www.youtube.com/channel/UCrK0KR016cpACKJ5jyy0MwQ,BocaSur +UCrYJpl5oC2ItVLPub5LVpWw,http://www.youtube.com/channel/UCrYJpl5oC2ItVLPub5LVpWw,Alecmolon +UCs2zbzxnFcilW4-2_yTXz-g,http://www.youtube.com/channel/UCs2zbzxnFcilW4-2_yTXz-g,SupraNews +UCsHaCORAuXxrMDzC0hr8GPw,http://www.youtube.com/channel/UCsHaCORAuXxrMDzC0hr8GPw,MxR Plays +UCsNqS-jSSdFRIvwmyd1nEVA,http://www.youtube.com/channel/UCsNqS-jSSdFRIvwmyd1nEVA,Sonter +UCsh1ax5Xk75-qjSGKVWxRDw,http://www.youtube.com/channel/UCsh1ax5Xk75-qjSGKVWxRDw,Nickel Firepower +UCsmx517WjzoyFuC17DGVt1A,http://www.youtube.com/channel/UCsmx517WjzoyFuC17DGVt1A,Wismichu +UCsvyYvzEG4YSuqxka__tkKQ,http://www.youtube.com/channel/UCsvyYvzEG4YSuqxka__tkKQ,Kalathras Zone +UCt-GOpCw4dOBlIyqL9A1ztA,http://www.youtube.com/channel/UCt-GOpCw4dOBlIyqL9A1ztA,Sr Pelo +UCt-dxEVG45pFcqtbOpXefBg,http://www.youtube.com/channel/UCt-dxEVG45pFcqtbOpXefBg,Sammwy +UCtMVHI3AJD4Qk4hcbZnI9ZQ,http://www.youtube.com/channel/UCtMVHI3AJD4Qk4hcbZnI9ZQ,SomeOrdinaryGamers +UCtOKlTUZUw41b1rz8t5ll1g,http://www.youtube.com/channel/UCtOKlTUZUw41b1rz8t5ll1g,TecnoSmart +UCtb8P4rf_1n8KS8eZk_lNNw,http://www.youtube.com/channel/UCtb8P4rf_1n8KS8eZk_lNNw,Fitz +UCtbN9AcvV2VndFQDTuahwtQ,http://www.youtube.com/channel/UCtbN9AcvV2VndFQDTuahwtQ,TENGU +UCu7TZ_ATWgjgD9IrNLdnYDA,http://www.youtube.com/channel/UCu7TZ_ATWgjgD9IrNLdnYDA,Little Big +UCv0jmyEcRipJqGV2i-P2jhA,http://www.youtube.com/channel/UCv0jmyEcRipJqGV2i-P2jhA,SHUNchan +UCv1Kcz-CuGM6mxzL3B1_Eiw,http://www.youtube.com/channel/UCv1Kcz-CuGM6mxzL3B1_Eiw,Gardiner Bryant +UCv6P5nsS9rP4tDtFlqLU_QQ,http://www.youtube.com/channel/UCv6P5nsS9rP4tDtFlqLU_QQ,ずっと真夜中でいいのに。 +UCvRihiQZiIO9RH2HOylfQ0Q,http://www.youtube.com/channel/UCvRihiQZiIO9RH2HOylfQ0Q,Snuffy +UCvnNkJsbONVhdXuHY_LpsdA,http://www.youtube.com/channel/UCvnNkJsbONVhdXuHY_LpsdA,ElRichMC - Minecraft & Gaming a otro nivel +UCw7CjJ7lFfpEC5FKmIS1ySw,http://www.youtube.com/channel/UCw7CjJ7lFfpEC5FKmIS1ySw,‏‏‎ +UCwGX2cE21VPBEJ49hcprP9w,http://www.youtube.com/channel/UCwGX2cE21VPBEJ49hcprP9w,SupraPixel +UCwNzCh6frugZA_cJk1LDUgA,http://www.youtube.com/channel/UCwNzCh6frugZA_cJk1LDUgA,Moai Gr +UCwi7FK3XDDwhioq1hV8Zmqg,http://www.youtube.com/channel/UCwi7FK3XDDwhioq1hV8Zmqg,La Zona Cero +UCwykB5130Xf1ck1T4zgG-nA,http://www.youtube.com/channel/UCwykB5130Xf1ck1T4zgG-nA,SLost +UCzFJ9ZkjYpxWTSqX9cVXj4g,http://www.youtube.com/channel/UCzFJ9ZkjYpxWTSqX9cVXj4g,tomiii 11 +UCzVn5MukMsABSfWktHaw-qw,http://www.youtube.com/channel/UCzVn5MukMsABSfWktHaw-qw,Soron +UCzXwjTI6c6mVn6oui_p6oiw,http://www.youtube.com/channel/UCzXwjTI6c6mVn6oui_p6oiw,SMii7Y + diff --git a/extractor/src/test/resources/youtube_takeout_import_test_2.zip b/extractor/src/test/resources/youtube_takeout_import_test_2.zip new file mode 100644 index 000000000..6ec565c7c Binary files /dev/null and b/extractor/src/test/resources/youtube_takeout_import_test_2.zip differ