Upload 27 files
Browse files- .gitignore +3 -0
- BUILD.md +53 -0
- CONTRIBUTING.md +15 -0
- Gemfile +2 -0
- LICENSE +21 -0
- PRIVACY.md +20 -0
- TERMS.md +5 -0
- _config.yml +3 -0
- _includes/format_share.html +20 -0
- _layouts/default.html +105 -0
- bulk.html +214 -0
- css/youtube-metadata.css +177 -0
- img/icon.pdn +0 -0
- img/icon.png +0 -0
- img/metadata.png +0 -0
- img/readme.png +0 -0
- index.html +142 -19
- js/bcp-47-translator.js +22 -0
- js/iso-3166-translator.js +1275 -0
- js/iso-639-translator.js +2362 -0
- js/randojs-2.0.0.js +6 -0
- js/shared.js +145 -0
- js/youtube-api-v3.js +71 -0
- js/youtube-metadata-bulk.js +0 -0
- js/youtube-metadata-examples.js +0 -0
- js/youtube-metadata.js +1868 -0
- js/yt-category-translator.js +350 -0
.gitignore
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.idea/
|
| 2 |
+
_site/
|
| 3 |
+
gemfile.lock
|
BUILD.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Build Documentation
|
| 2 |
+
=
|
| 3 |
+
|
| 4 |
+
### Setup
|
| 5 |
+
|
| 6 |
+
Get a copy of the repository
|
| 7 |
+
|
| 8 |
+
```
|
| 9 |
+
git clone https://github.com/mattwright324/youtube-metadata.git
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
Install Ruby (and gems jekyll and bundler) following the steps for your operating system
|
| 13 |
+
|
| 14 |
+
- https://jekyllrb.com/docs/installation/
|
| 15 |
+
- Ruby+Devkit default settings
|
| 16 |
+
- `gem install jekyll bundler`
|
| 17 |
+
|
| 18 |
+
In CMD or terminal, cd to the project directory you cloned to and run `bundle install` to install necessary gems
|
| 19 |
+
for github-pages in the project Gemfile (this may take some time).
|
| 20 |
+
|
| 21 |
+
### Build and Run
|
| 22 |
+
|
| 23 |
+
In CMD or terminal, cd to the project directory you cloned to and run `bundle exec jekyll serve`
|
| 24 |
+
and you can view a live version at http://localhost:4000
|
| 25 |
+
|
| 26 |
+
Update the application with any editor you prefer (WebStorm, VSCode, Notepad++, etc.), Jekyll works such that edits to files
|
| 27 |
+
made while it is running will be picked up and published only needing you to refresh the browser instance to see them.
|
| 28 |
+
|
| 29 |
+
*Note: My YouTube API key provided in the application is restricted only to `https://mattw.io/*`, `http://localhost:4000/*`, and `http://127.0.0.1:4000/*`.
|
| 30 |
+
Access should work for all local development. Please do not abuse it such that it uses up the daily quota.*
|
| 31 |
+
|
| 32 |
+
### Deployment note
|
| 33 |
+
|
| 34 |
+
If you are planning to deploy your own version of this application on another domain you will need your own YouTube and Maps API keys.
|
| 35 |
+
|
| 36 |
+
- https://console.cloud.google.com/apis/dashboard
|
| 37 |
+
- https://developers.google.com/youtube/v3/getting-started
|
| 38 |
+
- https://console.cloud.google.com/google/maps-apis/start
|
| 39 |
+
|
| 40 |
+
You can replace the YouTube API key in `youtube-api-v3.js` and replace the final line as such:
|
| 41 |
+
|
| 42 |
+
```js
|
| 43 |
+
youtube.setDefaultKey('AIzaSy...');
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
You can replace the Maps API key in `youtube-metadata.js` by searching for `maps.googleapis.com`.
|
| 47 |
+
|
| 48 |
+
It will also be important to note that the current YouTube API quota for new project keys is 10,000 units per day and may not be enough for your desired usage or if you plan to share your version.
|
| 49 |
+
My keys were lucky enough to be grandfathered in when the default quota limit was 1,000,000 units per day.
|
| 50 |
+
There is a process to request for more quota, however I have had not luck with it in the past.
|
| 51 |
+
|
| 52 |
+
- https://developers.google.com/youtube/v3/determine_quota_cost
|
| 53 |
+
- https://support.google.com/youtube/contact/yt_api_form
|
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Contributing Documentation
|
| 2 |
+
=
|
| 3 |
+
|
| 4 |
+
Contributions are certainly welcome and encouraged.
|
| 5 |
+
|
| 6 |
+
This application is hosted by [GitHub Pages](https://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages/getting-started-with-github-pages)
|
| 7 |
+
meaning the `master` branch is what GitHub uses to deploy the application as found at https://mattw.io/youtube-metadata.
|
| 8 |
+
|
| 9 |
+
Pull requests should generally describe the changes being made or the issue being addressed.
|
| 10 |
+
Pull requests should be merged into the `develop` branch so that I may make any additional tweaks or adjustments before
|
| 11 |
+
merging into `master` for GitHub Pages to deploy.
|
| 12 |
+
|
| 13 |
+
Make the pull request from your own fork of the project.
|
| 14 |
+
It is recommended to base it off the `develop` branch.
|
| 15 |
+
However, depending how involved you would like to be, I can consider adding you to the main project if asked.
|
Gemfile
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
source 'https://rubygems.org'
|
| 2 |
+
gem 'github-pages'
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2020 Matthew Wright
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
PRIVACY.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Privacy
|
| 2 |
+
|
| 3 |
+
This application uses YouTube API Services and Google Maps Services.
|
| 4 |
+
|
| 5 |
+
- http://www.google.com/policies/privacy
|
| 6 |
+
|
| 7 |
+
Basic user data is stored/collected by Google Analytics and Plausible and is being used for monitoring traffic and referrals.
|
| 8 |
+
Data collected by these services is not being shared with any other parties.
|
| 9 |
+
This application does not allow third parties to serve advertisements.
|
| 10 |
+
|
| 11 |
+
- http://www.google.com/policies/privacy
|
| 12 |
+
- https://plausible.io/privacy
|
| 13 |
+
|
| 14 |
+
Additional external calls are made to Filmot for archived video metadata.
|
| 15 |
+
|
| 16 |
+
- https://filmot.com/privacy
|
| 17 |
+
|
| 18 |
+
Additional external calls are made to my Heroku [cors-anywhere](https://github.com/Rob--W/cors-anywhere) proxy to resolve custom channel URLs to channel ids.
|
| 19 |
+
|
| 20 |
+
- https://www.heroku.com/policy/security
|
TERMS.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Terms of Use
|
| 2 |
+
|
| 3 |
+
By using this application you are agreeing to be bound by YouTube's Terms of Service
|
| 4 |
+
|
| 5 |
+
- https://www.youtube.com/t/terms
|
_config.yml
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
encoding : UTF-8
|
| 2 |
+
exclude : [.idea]
|
| 3 |
+
github : https://github.com/mattwright324/
|
_includes/format_share.html
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div class="container mb-15" style="margin-top: 1.25%">
|
| 2 |
+
<span>Accepted formats</span>
|
| 3 |
+
<ul id="formats" class="collapse show" style="padding-top:7px">
|
| 4 |
+
<li><span class="optional">https://www.</span>youtube.com/watch?v=<span class="orange">video_id</span></li>
|
| 5 |
+
<li><span class="optional">https://</span>youtube.com/shorts/<span class="orange">video_id</span></li>
|
| 6 |
+
<li><span class="optional">https://</span>youtu.be/<span class="orange">video_id</span></li>
|
| 7 |
+
<li><span class="optional">https://www.</span>youtube.com/playlist?list=<span class="orange">playlist_id</span></li>
|
| 8 |
+
<li><span class="optional">https://www.</span>youtube.com/channel/<span class="orange">channel_id</span></li>
|
| 9 |
+
<li><span class="optional">https://www.</span>youtube.com/user/<span class="orange">username</span></li>
|
| 10 |
+
<li><span class="optional">https://www.</span>youtube.com/@<span class="orange">channel_handle</span>
|
| 11 |
+
<li><span class="optional">https://www.</span>youtube.com/c/<span class="orange">custom_url</span></li>
|
| 12 |
+
<li><span class="optional">https://www.</span>youtube.com/<span class="orange">custom_url</span></li>
|
| 13 |
+
<li>
|
| 14 |
+
Also accepts direct ids:
|
| 15 |
+
<span class="orange">video_id</span>,
|
| 16 |
+
<span class="orange">playlist_id</span>,
|
| 17 |
+
<span class="orange">channel_id</span>
|
| 18 |
+
</li>
|
| 19 |
+
</ul>
|
| 20 |
+
</div>
|
_layouts/default.html
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en" class="dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="description"
|
| 6 |
+
content="Quickly gather all the metadata about a video, playlist, or channel from the YouTube API. Reverse image search thumbnails, geolocate in google maps, and translate ISO country and language codes.">
|
| 7 |
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
| 8 |
+
<link rel="icon" href="./img/icon.png">
|
| 9 |
+
<title>{{ page.title }}</title>
|
| 10 |
+
|
| 11 |
+
<link rel="preconnect" href="//cdn.jsdelivr.net" crossorigin>
|
| 12 |
+
|
| 13 |
+
<!-- Dependencies -->
|
| 14 |
+
<link href="//cdn.datatables.net/1.11.3/css/dataTables.bootstrap5.min.css" rel="stylesheet">
|
| 15 |
+
<link href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.3.1/build/styles/stackoverflow-dark.min.css" rel="stylesheet"
|
| 16 |
+
id="highlightjs-theme">
|
| 17 |
+
<link href="//cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/css/bootstrap-nightshade.min.css" rel="stylesheet">
|
| 18 |
+
<link href="//cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css" rel="stylesheet">
|
| 19 |
+
<link href="./css/youtube-metadata.css?v={{ site.time | date_to_xmlschema }}" rel="stylesheet"/>
|
| 20 |
+
<script src="//code.jquery.com/jquery-3.6.0.min.js"></script>
|
| 21 |
+
<script src="//cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
|
| 22 |
+
<script src="//cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.js"></script>
|
| 23 |
+
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.3.1/build/highlight.min.js"></script>
|
| 24 |
+
<script src="//cdn.jsdelivr.net/npm/apexcharts@3.32.0/dist/apexcharts.min.js"></script>
|
| 25 |
+
<script src="//cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/js/darkmode.min.js"></script>
|
| 26 |
+
<script src="//cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
| 27 |
+
<script src="//cdn.jsdelivr.net/npm/bootstrap-multiselect@1.1.0/dist/js/bootstrap-multiselect.min.js"></script>
|
| 28 |
+
<script src="//cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js"></script>
|
| 29 |
+
<script src="//cdn.jsdelivr.net/npm/file-saver@2.0.5/dist/FileSaver.min.js"></script>
|
| 30 |
+
<script src="//cdn.jsdelivr.net/npm/jszip-utils@0.1.0/dist/jszip-utils.min.js"></script>
|
| 31 |
+
<script src="//cdn.jsdelivr.net/npm/jszip@3.7.1/dist/jszip.min.js"></script>
|
| 32 |
+
<script src="//cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" type="text/javascript"></script>
|
| 33 |
+
<script src="//cdn.jsdelivr.net/npm/xregexp@5.1.0/xregexp-all.js"></script>
|
| 34 |
+
<script src="./js/randojs-2.0.0.js"></script>
|
| 35 |
+
|
| 36 |
+
<!-- App -->
|
| 37 |
+
<script src="./js/iso-639-translator.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 38 |
+
<script src="./js/iso-3166-translator.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 39 |
+
<script src="./js/bcp-47-translator.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 40 |
+
<script src="./js/yt-category-translator.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 41 |
+
<script src="./js/youtube-api-v3.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 42 |
+
<script src="./js/youtube-metadata-examples.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 43 |
+
<script src="./js/shared.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 44 |
+
<script src="./js/{{ page.script }}.js?v={{ site.time | date_to_xmlschema }}" type="text/javascript"></script>
|
| 45 |
+
|
| 46 |
+
<!-- Analytics -->
|
| 47 |
+
<script defer data-domain="mattw.io" src="https://plausible.io/js/plausible.js"></script>
|
| 48 |
+
</head>
|
| 49 |
+
<body>
|
| 50 |
+
<nav class="navbar navbar-expand-lg navbar-light mb-15" style="border-bottom: 1px solid rgba(127,127,127,0.1);">
|
| 51 |
+
<div class="container">
|
| 52 |
+
<div class="navbar-brand">
|
| 53 |
+
<img src="./img/icon.png" alt="" class="d-inline-block align-text-top">
|
| 54 |
+
<span style="padding-left: .75rem;">{{ page.title }}</span>
|
| 55 |
+
</div>
|
| 56 |
+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
|
| 57 |
+
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
| 58 |
+
<span class="navbar-toggler-icon"></span>
|
| 59 |
+
</button>
|
| 60 |
+
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
| 61 |
+
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
| 62 |
+
<li class="nav-item">
|
| 63 |
+
<a class="nav-link" href="./">Normal</a>
|
| 64 |
+
</li>
|
| 65 |
+
<li class="nav-item">
|
| 66 |
+
<a class="nav-link" href="./bulk">Bulk</a>
|
| 67 |
+
</li>
|
| 68 |
+
</ul>
|
| 69 |
+
<form class="d-flex">
|
| 70 |
+
<div class="form-check form-switch">
|
| 71 |
+
<input class="form-check-input" type="checkbox" role="switch" id="darkMode" checked>
|
| 72 |
+
<label class="form-check-label" for="darkMode">Dark</label>
|
| 73 |
+
</div>
|
| 74 |
+
<script>
|
| 75 |
+
const switchDarkMode = document.querySelector("#darkMode");
|
| 76 |
+
switchDarkMode.onclick = function (e) {
|
| 77 |
+
darkmode.toggleDarkMode();
|
| 78 |
+
}
|
| 79 |
+
window.addEventListener('DOMContentLoaded', () => {
|
| 80 |
+
if (DarkMode.getColorScheme() === "dark") {
|
| 81 |
+
console.log(1)
|
| 82 |
+
switchDarkMode.setAttribute("checked", "checked");
|
| 83 |
+
} else {
|
| 84 |
+
console.log(2)
|
| 85 |
+
switchDarkMode.removeAttribute("checked");
|
| 86 |
+
}
|
| 87 |
+
});
|
| 88 |
+
</script>
|
| 89 |
+
</form>
|
| 90 |
+
</div>
|
| 91 |
+
</div>
|
| 92 |
+
</nav>
|
| 93 |
+
{{ content }}
|
| 94 |
+
<div class="ui container" style="padding-top:3%;padding-bottom:3%;color:darkgray;text-align:center">
|
| 95 |
+
<img src="https://developers.google.com/static/youtube/images/developed-with-youtube-sentence-case-light.png" style="width:200px!important"/>
|
| 96 |
+
<br>
|
| 97 |
+
mattwright324 | 2023 | <a href="/">home</a> | <a href="https://github.com/mattwright324">github</a> |
|
| 98 |
+
<a href="https://github.com/mattwright324/youtube-metadata">youtube-metadata</a>
|
| 99 |
+
<br>
|
| 100 |
+
<a href="https://github.com/mattwright324/youtube-metadata/blob/master/PRIVACY.md">privacy</a> |
|
| 101 |
+
<a href="https://github.com/mattwright324/youtube-metadata/blob/master/TERMS.md">terms of use</a> |
|
| 102 |
+
<a href="/">contact</a>
|
| 103 |
+
</div>
|
| 104 |
+
</body>
|
| 105 |
+
</html>
|
bulk.html
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
layout: default
|
| 3 |
+
title: MW Metadata Bulk
|
| 4 |
+
script: youtube-metadata-bulk
|
| 5 |
+
---
|
| 6 |
+
<div class="container">
|
| 7 |
+
<p>
|
| 8 |
+
MW Metadata bulk grabs details about multiple YouTube videos, a playlist's videos, or a channel's public videos.
|
| 9 |
+
</p>
|
| 10 |
+
<p>
|
| 11 |
+
Submit a comma or whitespace separated list of multiple videos, playlists, or channels
|
| 12 |
+
</p>
|
| 13 |
+
<div class="input-group mb-3">
|
| 14 |
+
<input type="text" class="form-control" placeholder="https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
|
| 15 |
+
aria-label="https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw" aria-describedby="submit"
|
| 16 |
+
id="value" autocomplete="off">
|
| 17 |
+
<button class="btn btn-primary loading disabled" type="button" id="submit">
|
| 18 |
+
<span>Submit</span>
|
| 19 |
+
<span class="countdown"></span>
|
| 20 |
+
</button>
|
| 21 |
+
</div>
|
| 22 |
+
<div class="form-check">
|
| 23 |
+
<input class="form-check-input" type="checkbox" value="" id="createdPlaylists" autocomplete="off">
|
| 24 |
+
<label class="form-check-label" for="createdPlaylists">
|
| 25 |
+
Inspect videos in created playlists to find unlisted, private, and deleted videos (channels only)
|
| 26 |
+
</label>
|
| 27 |
+
</div>
|
| 28 |
+
</div>
|
| 29 |
+
{% include format_share.html %}
|
| 30 |
+
<div class="container mb-15">
|
| 31 |
+
<h2><span class="export">Export &</span> Share</h2>
|
| 32 |
+
<p class="export">Save this result as a zip file or load from a previous export. Drag and drop supported.</p>
|
| 33 |
+
<button class="btn btn-secondary export" id="export">
|
| 34 |
+
<span class="spinner"><span class="spinner-border spinner-border-sm" role="status"></span></span>
|
| 35 |
+
<span class="text"><i class="bi bi-download"></i> Export</span>
|
| 36 |
+
</button><span class="export"> </span>
|
| 37 |
+
<button class="btn btn-secondary export" id="import" onclick="document.getElementById('importFileChooser').click()">
|
| 38 |
+
<span class="spinner"><span class="spinner-border spinner-border-sm" role="status"></span></span>
|
| 39 |
+
<span class="text"><i class="bi bi-upload"></i> Import</span>
|
| 40 |
+
<input id="importFileChooser" type="file" hidden/>
|
| 41 |
+
</button>
|
| 42 |
+
<div class="form-check export" style="margin:10px 0">
|
| 43 |
+
<input class="form-check-input" type="checkbox" value="" id="includeThumbs" autocomplete="off">
|
| 44 |
+
<label class="form-check-label" for="includeThumbs">
|
| 45 |
+
Include thumbnails on export (this may take a long time)
|
| 46 |
+
<span id="thumbProgress" class="orange"></span>
|
| 47 |
+
</label>
|
| 48 |
+
</div>
|
| 49 |
+
<p class="export">Contains file(s)</p>
|
| 50 |
+
<ul class="export">
|
| 51 |
+
<li>about.txt - Metadata about this result.</li>
|
| 52 |
+
<li>videos.json - Array of all raw video data.</li>
|
| 53 |
+
<li>channels.json - Array of all raw channel data.</li>
|
| 54 |
+
<li>playlists.json - Array of all raw playlist data.</li>
|
| 55 |
+
<li>unavailable.json - Basic data for unavailable videos.</li>
|
| 56 |
+
<li>✱.csv - Data from each table section below.</li>
|
| 57 |
+
<li>thumbs/✱.png - Thumbs if available.</li>
|
| 58 |
+
</ul>
|
| 59 |
+
<p class="export"></p>
|
| 60 |
+
<p>Share this result:</p>
|
| 61 |
+
<div class="input-group" style="max-width: 226px;">
|
| 62 |
+
<input type="text" class="form-control" aria-describedby="copy" id="shareLink" autocomplete="off">
|
| 63 |
+
<button class="btn btn-primary clipboard" type="button" data-clipboard-target="#shareLink"><i
|
| 64 |
+
class="bi bi-clipboard"></i></button>
|
| 65 |
+
</div>
|
| 66 |
+
<p style="margin-top: 10px">
|
| 67 |
+
<a target="_blank" href="https://github.com/mattwright324/youtube-metadata/discussions/150">
|
| 68 |
+
What happened to export?
|
| 69 |
+
</a>
|
| 70 |
+
</p>
|
| 71 |
+
</div>
|
| 72 |
+
<div class="container mb-15">
|
| 73 |
+
<h2>Videos</h2>
|
| 74 |
+
<p>
|
| 75 |
+
List of all videos, playlist videos, or channel public uploads.
|
| 76 |
+
Customize columns to show more or less data as needed.
|
| 77 |
+
</p>
|
| 78 |
+
<div class="progress" style="margin-bottom:5px">
|
| 79 |
+
<div id="progressBar" class="progress-bar" role="progressbar" style="" aria-valuenow="0" aria-valuemin="0"
|
| 80 |
+
aria-valuemax="100">
|
| 81 |
+
<div class="label"></div>
|
| 82 |
+
</div>
|
| 83 |
+
</div>
|
| 84 |
+
<div id="progressText" style="width: 100%;text-align: center;">Idle</div>
|
| 85 |
+
<br>
|
| 86 |
+
<label for="column-options">Select column(s)</label>
|
| 87 |
+
<select id="column-options" multiple="multiple" hidden></select>
|
| 88 |
+
</div>
|
| 89 |
+
<div class="container-fluid mb-15">
|
| 90 |
+
<table id="videosTable" class="table table-striped table-hover" style="width:100%"></table>
|
| 91 |
+
</div>
|
| 92 |
+
<div class="container mb-15">
|
| 93 |
+
<h2>Tags</h2>
|
| 94 |
+
<p>Aggregate total tag counts on found videos.</p>
|
| 95 |
+
<table id="tagsTable" class="table table-striped table-hover" style="width:100%"></table>
|
| 96 |
+
</div>
|
| 97 |
+
<div class="container mb-15">
|
| 98 |
+
<h2>Geotags</h2>
|
| 99 |
+
<p>
|
| 100 |
+
Aggregate total geotag counts on found videos.
|
| 101 |
+
Want to visualize this data in a map?
|
| 102 |
+
Export this result and import the zip into
|
| 103 |
+
<a href="https://mattw.io/youtube-geofind" target="_blank">YouTube Geofind</a>!</p>
|
| 104 |
+
</p>
|
| 105 |
+
<table id="geotagsTable" class="table table-striped table-hover" style="width:100%"></table>
|
| 106 |
+
</div>
|
| 107 |
+
<div class="container mb-15">
|
| 108 |
+
<h2>Links</h2>
|
| 109 |
+
<p>
|
| 110 |
+
Aggregate total link counts in found video descriptions.
|
| 111 |
+
Be careful visiting what may show up here, by default results will not be hyperlinked for safety.
|
| 112 |
+
</p>
|
| 113 |
+
<div class="form-check mb-15">
|
| 114 |
+
<input class="form-check-input" type="checkbox" value="" id="makeHyperlinks" autocomplete="off"
|
| 115 |
+
onchange="bulk.toggleLinksColumn(0);bulk.toggleLinksColumn(1)">
|
| 116 |
+
<label class="form-check-label" for="makeHyperlinks">
|
| 117 |
+
Make them hyperlinks anyways
|
| 118 |
+
</label>
|
| 119 |
+
</div>
|
| 120 |
+
<table id="linksTable" class="table table-striped table-hover" style="width:100%"></table>
|
| 121 |
+
</div>
|
| 122 |
+
<div class="container mb-15">
|
| 123 |
+
<h2>Upload Frequency</h2>
|
| 124 |
+
<p>
|
| 125 |
+
Aggregate uploads frequency by hour and day.
|
| 126 |
+
Transformable to any timezone
|
| 127 |
+
(<a target="_blank" href="https://upload.wikimedia.org/wikipedia/commons/8/88/World_Time_Zones_Map.png">map</a>)
|
| 128 |
+
and filterable by year when activity occurred.
|
| 129 |
+
Guesstimate region using typical sleep/activity patterns, see change in behavior over time,
|
| 130 |
+
or see typical upload times in your own timezone.
|
| 131 |
+
</p>
|
| 132 |
+
<div class="row" style="margin: 0 0 1.5em 0">
|
| 133 |
+
<select id="offset" class="form-select" style="width:auto;margin-right:10px" autocomplete="off">
|
| 134 |
+
<option value="-1200">UTC −12:00</option>
|
| 135 |
+
<option value="-1100">UTC −11:00</option>
|
| 136 |
+
<option value="-1000">UTC −10:00</option>
|
| 137 |
+
<option value="-0930">UTC −09:30</option>
|
| 138 |
+
<option value="-0900">UTC −09:00</option>
|
| 139 |
+
<option value="-0800">UTC −08:00</option>
|
| 140 |
+
<option value="-0700">UTC −07:00</option>
|
| 141 |
+
<option value="-0600">UTC −06:00</option>
|
| 142 |
+
<option value="-0500">UTC −05:00</option>
|
| 143 |
+
<option value="-0400">UTC −04:00</option>
|
| 144 |
+
<option value="-0330">UTC −03:30</option>
|
| 145 |
+
<option value="-0300">UTC −03:00</option>
|
| 146 |
+
<option value="-0200">UTC −02:00</option>
|
| 147 |
+
<option value="-0100">UTC −01:00</option>
|
| 148 |
+
<option value="+0000" selected>UTC ±00:00</option>
|
| 149 |
+
<option value="+0100">UTC +01:00</option>
|
| 150 |
+
<option value="+0200">UTC +02:00</option>
|
| 151 |
+
<option value="+0300">UTC +03:00</option>
|
| 152 |
+
<option value="+0330">UTC +03:30</option>
|
| 153 |
+
<option value="+0400">UTC +04:00</option>
|
| 154 |
+
<option value="+0430">UTC +04:30</option>
|
| 155 |
+
<option value="+0500">UTC +05:00</option>
|
| 156 |
+
<option value="+0530">UTC +05:30</option>
|
| 157 |
+
<option value="+0545">UTC +05:45</option>
|
| 158 |
+
<option value="+0600">UTC +06:00</option>
|
| 159 |
+
<option value="+0630">UTC +06:30</option>
|
| 160 |
+
<option value="+0700">UTC +07:00</option>
|
| 161 |
+
<option value="+0800">UTC +08:00</option>
|
| 162 |
+
<option value="+0845">UTC +08:45</option>
|
| 163 |
+
<option value="+0900">UTC +09:00</option>
|
| 164 |
+
<option value="+0930">UTC +09:30</option>
|
| 165 |
+
<option value="+1000">UTC +10:00</option>
|
| 166 |
+
<option value="+1030">UTC +10:30</option>
|
| 167 |
+
<option value="+1100">UTC +11:00</option>
|
| 168 |
+
<option value="+1200">UTC +12:00</option>
|
| 169 |
+
<option value="+1245">UTC +12:45</option>
|
| 170 |
+
<option value="+1300">UTC +13:00</option>
|
| 171 |
+
<option value="+1345">UTC +13:45</option>
|
| 172 |
+
<option value="+1400">UTC +14:00</option>
|
| 173 |
+
</select>
|
| 174 |
+
<select id="year" class="form-select" style="width:auto" autocomplete="off">
|
| 175 |
+
<option value="" selected>All years</option>
|
| 176 |
+
</select>
|
| 177 |
+
</div>
|
| 178 |
+
<div id="uploadFrequency"></div>
|
| 179 |
+
</div>
|
| 180 |
+
<div class="container mb-15">
|
| 181 |
+
<h2>Unavailable</h2>
|
| 182 |
+
<p>
|
| 183 |
+
Videos that are unavailable from channels (created playlists on), playlists, or videos.
|
| 184 |
+
They are either <a target="_blank" href="https://github.com/mattwright324/youtube-metadata/wiki/Deleted-and-Private-Videos">deleted or made private</a>.
|
| 185 |
+
Consider searching for user-made playlists to find more unavailable videos.
|
| 186 |
+
</p>
|
| 187 |
+
<div id="unavailable">
|
| 188 |
+
<div class="input-group mb-3" style="align-items: center;">
|
| 189 |
+
<button class="btn btn-secondary loading disabled" type="button" id="checkUnavailable" style="margin-right: 10px">
|
| 190 |
+
<span>Check Unavailable</span>
|
| 191 |
+
<span class="countdown"></span>
|
| 192 |
+
</button>
|
| 193 |
+
<span>Check Filmot for any archived metadata for unavailable videos.</span>
|
| 194 |
+
</div>
|
| 195 |
+
<div class="progress" style="margin-bottom:5px">
|
| 196 |
+
<div id="unavailableProgressBar" class="progress-bar" role="progressbar" style="" aria-valuenow="0" aria-valuemin="0"
|
| 197 |
+
aria-valuemax="100">
|
| 198 |
+
<div class="label"></div>
|
| 199 |
+
</div>
|
| 200 |
+
</div>
|
| 201 |
+
<div id="unavailableProgressText" style="width: 100%;text-align: center;">Idle</div>
|
| 202 |
+
<br>
|
| 203 |
+
</div>
|
| 204 |
+
<label for="unavailable-columns">Select column(s)</label>
|
| 205 |
+
<select id="unavailable-columns" multiple="multiple" hidden></select>
|
| 206 |
+
</div>
|
| 207 |
+
<div class="container-fluid mb-15">
|
| 208 |
+
<table id="unavailableTable" class="table table-striped table-hover" style="width:100%"></table>
|
| 209 |
+
</div>
|
| 210 |
+
<div class="container mb-15">
|
| 211 |
+
<h2>Other</h2>
|
| 212 |
+
<p>Other potentially useful aggregate data on found videos.</p>
|
| 213 |
+
<table id="otherTable" class="table table-striped table-hover" style="width:100%"></table>
|
| 214 |
+
</div>
|
css/youtube-metadata.css
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
body {
|
| 2 |
+
background-repeat: repeat;
|
| 3 |
+
font-weight: 350 !important;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
a[href] {
|
| 7 |
+
text-decoration: none;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
ul {
|
| 11 |
+
line-height: 20px;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
code {
|
| 15 |
+
max-height: 180px;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
.mb-15 {
|
| 19 |
+
margin-bottom: 1.5%;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
p.mb-15 {
|
| 23 |
+
margin-bottom: 0.75%;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
.mt-15 {
|
| 27 |
+
margin-top: 1.5%;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
.pt-15 {
|
| 31 |
+
padding-top: 1.5%;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.navbar-brand {
|
| 35 |
+
font-size: 1.75rem!important;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.navbar {
|
| 39 |
+
font-size: 1.5rem!important;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
.orange {
|
| 43 |
+
color: orange;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
.red {
|
| 47 |
+
color: red;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
.green {
|
| 51 |
+
color: green;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
.optional {
|
| 55 |
+
opacity: 0.75;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
.section-header {
|
| 59 |
+
font-size: 1.5em;
|
| 60 |
+
margin: 0 0 0.3em;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
.unknown {
|
| 64 |
+
color: mediumpurple;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.good {
|
| 68 |
+
color: mediumseagreen;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.bad, .gray {
|
| 72 |
+
color: lightgray;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
.profile {
|
| 76 |
+
width: 100px;
|
| 77 |
+
height: 100px;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
img {
|
| 81 |
+
width: 100%;
|
| 82 |
+
max-width: 500px;
|
| 83 |
+
height: auto;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
.navbar-brand img {
|
| 87 |
+
width: 40px !important;
|
| 88 |
+
height: 40px !important;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.section-header span {
|
| 92 |
+
margin-left: 8px;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
#export, #import {
|
| 96 |
+
width: 100px;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
button.loading .text {
|
| 100 |
+
display: none;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
.dropdown-toggle::after {
|
| 104 |
+
content: none
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
.progress {
|
| 108 |
+
height: 2em;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
.tag {
|
| 112 |
+
background-color: lightskyblue;
|
| 113 |
+
padding: 2px 5px;
|
| 114 |
+
border-radius: 5px;
|
| 115 |
+
margin-right: 4px;
|
| 116 |
+
margin-bottom: 3px;
|
| 117 |
+
display: inline-block;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
.comma {
|
| 121 |
+
color: transparent;
|
| 122 |
+
width: 0;
|
| 123 |
+
display: inline-block;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
button .countdown, button .spinner {
|
| 127 |
+
display: none;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
button.loading .countdown, button.loading .spinner {
|
| 131 |
+
display: initial;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
.progress-bar.error {
|
| 135 |
+
background-color: #e67e22;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
html.dark .progress-bar.error {
|
| 139 |
+
background-color: #ca6f1e;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
/* Dark mode tweaks */
|
| 143 |
+
html.dark .tag {
|
| 144 |
+
background-color: royalblue;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
html.dark .btn-primary {
|
| 148 |
+
background-color: #0d6efd;
|
| 149 |
+
border-color: #0d6efd;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
html.dark a {
|
| 153 |
+
color: lightskyblue;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
html.dark .progress-bar {
|
| 157 |
+
color: #fff;
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
.wayback-cdx-older {
|
| 161 |
+
filter: brightness(0.75);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
.export {
|
| 165 |
+
display: none;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
/*
|
| 169 |
+
Use Stylus extension!
|
| 170 |
+
|
| 171 |
+
https://chrome.google.com/webstore/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne
|
| 172 |
+
https://addons.mozilla.org/en-US/firefox/addon/styl-us/
|
| 173 |
+
|
| 174 |
+
.export {
|
| 175 |
+
display: revert!important;
|
| 176 |
+
}
|
| 177 |
+
*/
|
img/icon.pdn
ADDED
|
Binary file (14.8 kB). View file
|
|
|
img/icon.png
ADDED
|
|
img/metadata.png
ADDED
|
img/readme.png
ADDED
|
index.html
CHANGED
|
@@ -1,19 +1,142 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
layout: default
|
| 3 |
+
title: MW Metadata
|
| 4 |
+
script: youtube-metadata
|
| 5 |
+
---
|
| 6 |
+
<div class="container">
|
| 7 |
+
<p>
|
| 8 |
+
MW Metadata normal grabs singular details about a YouTube video and its uploader, playlist and its creator, or channel.
|
| 9 |
+
</p>
|
| 10 |
+
<p>
|
| 11 |
+
Submit a link or id to a video, playlist, or channel
|
| 12 |
+
</p>
|
| 13 |
+
<div class="input-group">
|
| 14 |
+
<input type="text" class="form-control" placeholder="https://youtu.be/dQw4w9WgXcQ" autocomplete="off"
|
| 15 |
+
aria-label="https://youtu.be/dQw4w9WgXcQ" aria-describedby="submit" id="value">
|
| 16 |
+
<button class="btn btn-primary loading disabled" type="button" id="submit" >
|
| 17 |
+
<span>Submit</span>
|
| 18 |
+
<span class="countdown"></span>
|
| 19 |
+
</button>
|
| 20 |
+
</div>
|
| 21 |
+
</div>
|
| 22 |
+
{% include format_share.html %}
|
| 23 |
+
<div class="container mb-15">
|
| 24 |
+
<h2><span class="export">Export &</span> Share</h2>
|
| 25 |
+
<p class="export">Save this result as a zip file or load from a previous export. Drag and drop supported.</p>
|
| 26 |
+
<button class="btn btn-secondary export" id="export">
|
| 27 |
+
<span class="spinner"><span class="spinner-border spinner-border-sm" role="status"></span></span>
|
| 28 |
+
<span class="text"><i class="bi bi-download"></i> Export</span>
|
| 29 |
+
</button><span class="export"> </span>
|
| 30 |
+
<button class="btn btn-secondary export" id="import" onclick="document.getElementById('importFileChooser').click()">
|
| 31 |
+
<span class="spinner"><span class="spinner-border spinner-border-sm" role="status"></span></span>
|
| 32 |
+
<span class="text"><i class="bi bi-upload"></i> Import</span>
|
| 33 |
+
<input id="importFileChooser" type="file" hidden/>
|
| 34 |
+
</button>
|
| 35 |
+
<p class="export"></p>
|
| 36 |
+
<p class="export">Contains file(s)</p>
|
| 37 |
+
<ul class="export">
|
| 38 |
+
<li>about.txt - Metadata about this result.</li>
|
| 39 |
+
<li>video.json - Raw video data.</li>
|
| 40 |
+
<li>playlist.json - Raw playlist data.</li>
|
| 41 |
+
<li>channel.json - Raw channel data.</li>
|
| 42 |
+
<li>filmot.json - Archive data if retrieved.</li>
|
| 43 |
+
<li>✱-thumb.png - Thumbs if available.</li>
|
| 44 |
+
</ul>
|
| 45 |
+
<p class="export"></p>
|
| 46 |
+
<p>Share this result:</p>
|
| 47 |
+
<div class="input-group" style="max-width: 226px;">
|
| 48 |
+
<input type="text" class="form-control" aria-describedby="copy" id="shareLink" autocomplete="off">
|
| 49 |
+
<button class="btn btn-primary clipboard" type="button" data-clipboard-target="#shareLink"><i class="bi bi-clipboard"></i></button>
|
| 50 |
+
</div>
|
| 51 |
+
<p style="margin-top: 10px">
|
| 52 |
+
<a target="_blank" href="https://github.com/mattwright324/youtube-metadata/discussions/150">
|
| 53 |
+
What happened to export?
|
| 54 |
+
</a>
|
| 55 |
+
</p>
|
| 56 |
+
</div>
|
| 57 |
+
<div class="container mb-15" id="video">
|
| 58 |
+
<h2>Video</h2>
|
| 59 |
+
<p>The video submitted.
|
| 60 |
+
Click <a href="https://developers.google.com/youtube/v3/docs/videos#properties" target="_blank">here</a>
|
| 61 |
+
to see detailed property descriptions.
|
| 62 |
+
</p>
|
| 63 |
+
<div id="video-section"></div>
|
| 64 |
+
|
| 65 |
+
<div class='section-header unknown'><i class='bi bi-question-circle-fill'></i><span>Thumbnails</span></div>
|
| 66 |
+
<p>Reverse image search all four thumbnail images.</p>
|
| 67 |
+
<div id="thumbnails" class="row row-cols-4"></div>
|
| 68 |
+
|
| 69 |
+
<div class='section-header unknown'><i class='bi bi-question-circle-fill'></i><span>More</span></div>
|
| 70 |
+
<p>Check other resources for details or archival.</p>
|
| 71 |
+
<div id="video-more" style="padding-top:0"></div>
|
| 72 |
+
</div>
|
| 73 |
+
<div class="container mb-15" id="playlist">
|
| 74 |
+
<h2>Playlist</h2>
|
| 75 |
+
<p>The playlist submitted.
|
| 76 |
+
Click <a href="https://developers.google.com/youtube/v3/docs/playlists#properties"
|
| 77 |
+
target="_blank">here</a> to see detailed property descriptions.
|
| 78 |
+
</p>
|
| 79 |
+
<div id="playlist-section"></div>
|
| 80 |
+
|
| 81 |
+
<div class='section-header unknown'><i class='bi bi-question-circle-fill'></i><span>More</span></div>
|
| 82 |
+
<p>Check other resources for details or archival.</p>
|
| 83 |
+
<div id="playlist-more" style="padding-top:0"></div>
|
| 84 |
+
</div>
|
| 85 |
+
<div class="container mb-15" id="channel">
|
| 86 |
+
<h2>Channel</h2>
|
| 87 |
+
<p>The video author, playlist creator, or channel submitted.
|
| 88 |
+
Click <a href="https://developers.google.com/youtube/v3/docs/channels#properties" target="_blank">here</a>
|
| 89 |
+
to see detailed property descriptions.
|
| 90 |
+
</p>
|
| 91 |
+
<div id="channel-section"></div>
|
| 92 |
+
|
| 93 |
+
<div class='section-header unknown'><i class='bi bi-question-circle-fill'></i><span>More</span></div>
|
| 94 |
+
<p>Check other resources for details or archival.</p>
|
| 95 |
+
<div id="channel-more" style="padding-top:0"></div>
|
| 96 |
+
</div>
|
| 97 |
+
<div class="container mb-15" id="unknown" style="display: none">
|
| 98 |
+
<h2>Unknown</h2>
|
| 99 |
+
<p id="reason" class="mb-15"></p>
|
| 100 |
+
<div id="reason-append"></div>
|
| 101 |
+
</div>
|
| 102 |
+
<div class="container mb-15" id="quota" style="display: none">
|
| 103 |
+
<h2>Quota Exceeded</h2>
|
| 104 |
+
<p class="mb-15">
|
| 105 |
+
The daily YouTube API quota has been reached for this application.
|
| 106 |
+
Quota resets at <span class="orange">midnight Pacific Time (PT)</span> as per the Google Developers Console.
|
| 107 |
+
</p>
|
| 108 |
+
<p class="mb-15">
|
| 109 |
+
See more detail here with
|
| 110 |
+
<a href="https://github.com/mattwright324/youtube-metadata/issues/3" target="_blank">issue #3</a>.
|
| 111 |
+
</p>
|
| 112 |
+
<p class="mb-15">
|
| 113 |
+
Since the API is continually reaching its quota due to someone, you can use your own API key with this
|
| 114 |
+
<a href="https://github.com/mattwright324/youtube-metadata/issues/3#issuecomment-1532385453" target="_blank">
|
| 115 |
+
Tampermonkey userscript</a>.
|
| 116 |
+
<a href="https://developers.google.com/youtube/v3/getting-started#intro" target="_blank">
|
| 117 |
+
Here</a> to create your own key.
|
| 118 |
+
</p>
|
| 119 |
+
<div id="quota-reason-append"></div>
|
| 120 |
+
</div>
|
| 121 |
+
<div class="container mb-15" id="filmot" style="display: none">
|
| 122 |
+
<h2>Filmot Archive</h2>
|
| 123 |
+
<p class="mb-15">
|
| 124 |
+
Data retrieved from Filmot about this unavailable video.
|
| 125 |
+
</p>
|
| 126 |
+
<div id="filmot-append"></div>
|
| 127 |
+
</div>
|
| 128 |
+
<div class="container mb-15" id="wayback" style="display: none">
|
| 129 |
+
<h2>Wayback CDX</h2>
|
| 130 |
+
<p class="mb-15">
|
| 131 |
+
Potential metadata returned from Wayback CDX API. Searches for video and video storyboard thumbnails.
|
| 132 |
+
</p>
|
| 133 |
+
<button class="btn btn-secondary" id="wayback-check" style="margin-bottom:8px">Check CDX</button>
|
| 134 |
+
<div id="wayback-show-older" class="form-check" style="margin-bottom:8px;display:none">
|
| 135 |
+
<input class="form-check-input" type="checkbox" value="" id="checkHideOlder" checked>
|
| 136 |
+
<label class="form-check-label" for="checkHideOlder">
|
| 137 |
+
Hide older versions of the same link (<span class="older-count">0</span> older)
|
| 138 |
+
</label>
|
| 139 |
+
</div>
|
| 140 |
+
<div id="wayback-append"></div>
|
| 141 |
+
<button class="btn btn-secondary" id="wayback-copy" style="margin-bottom:8px;display:none">Copy visible links</button>
|
| 142 |
+
</div>
|
js/bcp-47-translator.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* BCP 47 is a combination of country code ISO 3166 and language code ISO 639.
|
| 3 |
+
*
|
| 4 |
+
* This translates both codes.
|
| 5 |
+
*/
|
| 6 |
+
const bcp47 = (function (iso3166, iso639) {
|
| 7 |
+
'use strict';
|
| 8 |
+
|
| 9 |
+
return {
|
| 10 |
+
lookup: function (code) {
|
| 11 |
+
if (!code) {
|
| 12 |
+
return;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
const parts = String(code).split(/[-|_]/);
|
| 16 |
+
return {
|
| 17 |
+
language: iso639.lookup(parts[0]) || iso639.lookup(parts[1]),
|
| 18 |
+
country: iso3166.lookup(parts[0]) || iso3166.lookup(parts[1])
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
}(iso3166, iso639));
|
js/iso-3166-translator.js
ADDED
|
@@ -0,0 +1,1275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Implementation to quickly translate ISO 3166-1 two and three letter and digit country codes.
|
| 3 |
+
*
|
| 4 |
+
* @link https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
|
| 5 |
+
*/
|
| 6 |
+
const iso3166 = (function () {
|
| 7 |
+
'use strict';
|
| 8 |
+
|
| 9 |
+
const codes = [
|
| 10 |
+
{
|
| 11 |
+
"name": "Afghanistan",
|
| 12 |
+
"numeric3": "004",
|
| 13 |
+
"alpha2": "AF"
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"name": "Åland Islands",
|
| 17 |
+
"numeric3": "248",
|
| 18 |
+
"alpha2": "AX"
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"name": "Albania",
|
| 22 |
+
"numeric3": "008",
|
| 23 |
+
"alpha2": "AL"
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"name": "Algeria",
|
| 27 |
+
"numeric3": "012",
|
| 28 |
+
"alpha2": "DZ"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"name": "American Samoa",
|
| 32 |
+
"numeric3": "016",
|
| 33 |
+
"alpha2": "AS"
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"name": "Andorra",
|
| 37 |
+
"numeric3": "020",
|
| 38 |
+
"alpha2": "AD"
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"name": "Angola",
|
| 42 |
+
"numeric3": "024",
|
| 43 |
+
"alpha2": "AO"
|
| 44 |
+
},
|
| 45 |
+
{
|
| 46 |
+
"name": "Anguilla",
|
| 47 |
+
"numeric3": "660",
|
| 48 |
+
"alpha2": "AI"
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"name": "Antarctica",
|
| 52 |
+
"numeric3": "010",
|
| 53 |
+
"alpha2": "AQ"
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"name": "Antigua and Barbuda",
|
| 57 |
+
"numeric3": "028",
|
| 58 |
+
"alpha2": "AG"
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"name": "Argentina",
|
| 62 |
+
"numeric3": "032",
|
| 63 |
+
"alpha2": "AR"
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"name": "Armenia",
|
| 67 |
+
"numeric3": "051",
|
| 68 |
+
"alpha2": "AM"
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"name": "Aruba",
|
| 72 |
+
"numeric3": "533",
|
| 73 |
+
"alpha2": "AW"
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"name": "Australia",
|
| 77 |
+
"numeric3": "036",
|
| 78 |
+
"alpha2": "AU"
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"name": "Austria",
|
| 82 |
+
"numeric3": "040",
|
| 83 |
+
"alpha2": "AT"
|
| 84 |
+
},
|
| 85 |
+
{
|
| 86 |
+
"name": "Azerbaijan",
|
| 87 |
+
"numeric3": "031",
|
| 88 |
+
"alpha2": "AZ"
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"name": "Bahamas (the)",
|
| 92 |
+
"numeric3": "044",
|
| 93 |
+
"alpha2": "BS"
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"name": "Bahrain",
|
| 97 |
+
"numeric3": "048",
|
| 98 |
+
"alpha2": "BH"
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"name": "Bangladesh",
|
| 102 |
+
"numeric3": "050",
|
| 103 |
+
"alpha2": "BD"
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"name": "Barbados",
|
| 107 |
+
"numeric3": "052",
|
| 108 |
+
"alpha2": "BB"
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"name": "Belarus",
|
| 112 |
+
"numeric3": "112",
|
| 113 |
+
"alpha2": "BY"
|
| 114 |
+
},
|
| 115 |
+
{
|
| 116 |
+
"name": "Belgium",
|
| 117 |
+
"numeric3": "056",
|
| 118 |
+
"alpha2": "BE"
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"name": "Belize",
|
| 122 |
+
"numeric3": "084",
|
| 123 |
+
"alpha2": "BZ"
|
| 124 |
+
},
|
| 125 |
+
{
|
| 126 |
+
"name": "Benin",
|
| 127 |
+
"numeric3": "204",
|
| 128 |
+
"alpha2": "BJ"
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"name": "Bermuda",
|
| 132 |
+
"numeric3": "060",
|
| 133 |
+
"alpha2": "BM"
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"name": "Bhutan",
|
| 137 |
+
"numeric3": "064",
|
| 138 |
+
"alpha2": "BT"
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"name": "Bolivia (Plurinational State of)",
|
| 142 |
+
"numeric3": "068",
|
| 143 |
+
"alpha2": "BO"
|
| 144 |
+
},
|
| 145 |
+
{
|
| 146 |
+
"name": "Bonaire Sint Eustatius Saba",
|
| 147 |
+
"numeric3": "535",
|
| 148 |
+
"alpha2": "BQ"
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"name": "Bosnia and Herzegovina",
|
| 152 |
+
"numeric3": "070",
|
| 153 |
+
"alpha2": "BA"
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"name": "Botswana",
|
| 157 |
+
"numeric3": "072",
|
| 158 |
+
"alpha2": "BW"
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"name": "Bouvet Island",
|
| 162 |
+
"numeric3": "074",
|
| 163 |
+
"alpha2": "BV"
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"name": "Brazil",
|
| 167 |
+
"numeric3": "076",
|
| 168 |
+
"alpha2": "BR"
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"name": "British Indian Ocean Territory (the)",
|
| 172 |
+
"numeric3": "086",
|
| 173 |
+
"alpha2": "IO"
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
"name": "Brunei Darussalam",
|
| 177 |
+
"numeric3": "096",
|
| 178 |
+
"alpha2": "BN"
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
"name": "Bulgaria",
|
| 182 |
+
"numeric3": "100",
|
| 183 |
+
"alpha2": "BG"
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
"name": "Burkina Faso",
|
| 187 |
+
"numeric3": "854",
|
| 188 |
+
"alpha2": "BF"
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"name": "Burundi",
|
| 192 |
+
"numeric3": "108",
|
| 193 |
+
"alpha2": "BI"
|
| 194 |
+
},
|
| 195 |
+
{
|
| 196 |
+
"name": "Cabo Verde",
|
| 197 |
+
"numeric3": "132",
|
| 198 |
+
"alpha2": "CV"
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"name": "Cambodia",
|
| 202 |
+
"numeric3": "116",
|
| 203 |
+
"alpha2": "KH"
|
| 204 |
+
},
|
| 205 |
+
{
|
| 206 |
+
"name": "Cameroon",
|
| 207 |
+
"numeric3": "120",
|
| 208 |
+
"alpha2": "CM"
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"name": "Canada",
|
| 212 |
+
"numeric3": "124",
|
| 213 |
+
"alpha2": "CA"
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"name": "Cayman Islands (the)",
|
| 217 |
+
"numeric3": "136",
|
| 218 |
+
"alpha2": "KY"
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"name": "Central African Republic (the)",
|
| 222 |
+
"numeric3": "140",
|
| 223 |
+
"alpha2": "CF"
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"name": "Chad",
|
| 227 |
+
"numeric3": "148",
|
| 228 |
+
"alpha2": "TD"
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"name": "Chile",
|
| 232 |
+
"numeric3": "152",
|
| 233 |
+
"alpha2": "CL"
|
| 234 |
+
},
|
| 235 |
+
{
|
| 236 |
+
"name": "China",
|
| 237 |
+
"numeric3": "156",
|
| 238 |
+
"alpha2": "CN"
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"name": "Christmas Island",
|
| 242 |
+
"numeric3": "162",
|
| 243 |
+
"alpha2": "CX"
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"name": "Cocos (Keeling) Islands (the)",
|
| 247 |
+
"numeric3": "166",
|
| 248 |
+
"alpha2": "CC"
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"name": "Colombia",
|
| 252 |
+
"numeric3": "170",
|
| 253 |
+
"alpha2": "CO"
|
| 254 |
+
},
|
| 255 |
+
{
|
| 256 |
+
"name": "Comoros (the)",
|
| 257 |
+
"numeric3": "174",
|
| 258 |
+
"alpha2": "KM"
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
"name": "Congo (the Democratic Republic of the)",
|
| 262 |
+
"numeric3": "180",
|
| 263 |
+
"alpha2": "CD"
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"name": "Congo (the)",
|
| 267 |
+
"numeric3": "178",
|
| 268 |
+
"alpha2": "CG"
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"name": "Cook Islands (the)",
|
| 272 |
+
"numeric3": "184",
|
| 273 |
+
"alpha2": "CK"
|
| 274 |
+
},
|
| 275 |
+
{
|
| 276 |
+
"name": "Costa Rica",
|
| 277 |
+
"numeric3": "188",
|
| 278 |
+
"alpha2": "CR"
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"name": "Côte d'Ivoire",
|
| 282 |
+
"numeric3": "384",
|
| 283 |
+
"alpha2": "CI"
|
| 284 |
+
},
|
| 285 |
+
{
|
| 286 |
+
"name": "Croatia",
|
| 287 |
+
"numeric3": "191",
|
| 288 |
+
"alpha2": "HR"
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"name": "Cuba",
|
| 292 |
+
"numeric3": "192",
|
| 293 |
+
"alpha2": "CU"
|
| 294 |
+
},
|
| 295 |
+
{
|
| 296 |
+
"name": "Curaçao",
|
| 297 |
+
"numeric3": "531",
|
| 298 |
+
"alpha2": "CW"
|
| 299 |
+
},
|
| 300 |
+
{
|
| 301 |
+
"name": "Cyprus",
|
| 302 |
+
"numeric3": "196",
|
| 303 |
+
"alpha2": "CY"
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"name": "Czechia",
|
| 307 |
+
"numeric3": "203",
|
| 308 |
+
"alpha2": "CZ"
|
| 309 |
+
},
|
| 310 |
+
{
|
| 311 |
+
"name": "Denmark",
|
| 312 |
+
"numeric3": "208",
|
| 313 |
+
"alpha2": "DK"
|
| 314 |
+
},
|
| 315 |
+
{
|
| 316 |
+
"name": "Djibouti",
|
| 317 |
+
"numeric3": "262",
|
| 318 |
+
"alpha2": "DJ"
|
| 319 |
+
},
|
| 320 |
+
{
|
| 321 |
+
"name": "Dominica",
|
| 322 |
+
"numeric3": "212",
|
| 323 |
+
"alpha2": "DM"
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
"name": "Dominican Republic (the)",
|
| 327 |
+
"numeric3": "214",
|
| 328 |
+
"alpha2": "DO"
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"name": "Ecuador",
|
| 332 |
+
"numeric3": "218",
|
| 333 |
+
"alpha2": "EC"
|
| 334 |
+
},
|
| 335 |
+
{
|
| 336 |
+
"name": "Egypt",
|
| 337 |
+
"numeric3": "818",
|
| 338 |
+
"alpha2": "EG"
|
| 339 |
+
},
|
| 340 |
+
{
|
| 341 |
+
"name": "El Salvador",
|
| 342 |
+
"numeric3": "222",
|
| 343 |
+
"alpha2": "SV"
|
| 344 |
+
},
|
| 345 |
+
{
|
| 346 |
+
"name": "Equatorial Guinea",
|
| 347 |
+
"numeric3": "226",
|
| 348 |
+
"alpha2": "GQ"
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"name": "Eritrea",
|
| 352 |
+
"numeric3": "232",
|
| 353 |
+
"alpha2": "ER"
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"name": "Estonia",
|
| 357 |
+
"numeric3": "233",
|
| 358 |
+
"alpha2": "EE"
|
| 359 |
+
},
|
| 360 |
+
{
|
| 361 |
+
"name": "Eswatini",
|
| 362 |
+
"numeric3": "748",
|
| 363 |
+
"alpha2": "SZ"
|
| 364 |
+
},
|
| 365 |
+
{
|
| 366 |
+
"name": "Ethiopia",
|
| 367 |
+
"numeric3": "231",
|
| 368 |
+
"alpha2": "ET"
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"name": "Falkland Islands (the) Malvinas",
|
| 372 |
+
"numeric3": "238",
|
| 373 |
+
"alpha2": "FK"
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"name": "Faroe Islands (the)",
|
| 377 |
+
"numeric3": "234",
|
| 378 |
+
"alpha2": "FO"
|
| 379 |
+
},
|
| 380 |
+
{
|
| 381 |
+
"name": "Fiji",
|
| 382 |
+
"numeric3": "242",
|
| 383 |
+
"alpha2": "FJ"
|
| 384 |
+
},
|
| 385 |
+
{
|
| 386 |
+
"name": "Finland",
|
| 387 |
+
"numeric3": "246",
|
| 388 |
+
"alpha2": "FI"
|
| 389 |
+
},
|
| 390 |
+
{
|
| 391 |
+
"name": "France",
|
| 392 |
+
"numeric3": "250",
|
| 393 |
+
"alpha2": "FR"
|
| 394 |
+
},
|
| 395 |
+
{
|
| 396 |
+
"name": "French Guiana",
|
| 397 |
+
"numeric3": "254",
|
| 398 |
+
"alpha2": "GF"
|
| 399 |
+
},
|
| 400 |
+
{
|
| 401 |
+
"name": "French Polynesia",
|
| 402 |
+
"numeric3": "258",
|
| 403 |
+
"alpha2": "PF"
|
| 404 |
+
},
|
| 405 |
+
{
|
| 406 |
+
"name": "French Southern Territories (the)",
|
| 407 |
+
"numeric3": "260",
|
| 408 |
+
"alpha2": "TF"
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"name": "Gabon",
|
| 412 |
+
"numeric3": "266",
|
| 413 |
+
"alpha2": "GA"
|
| 414 |
+
},
|
| 415 |
+
{
|
| 416 |
+
"name": "Gambia (the)",
|
| 417 |
+
"numeric3": "270",
|
| 418 |
+
"alpha2": "GM"
|
| 419 |
+
},
|
| 420 |
+
{
|
| 421 |
+
"name": "Georgia",
|
| 422 |
+
"numeric3": "268",
|
| 423 |
+
"alpha2": "GE"
|
| 424 |
+
},
|
| 425 |
+
{
|
| 426 |
+
"name": "Germany",
|
| 427 |
+
"numeric3": "276",
|
| 428 |
+
"alpha2": "DE"
|
| 429 |
+
},
|
| 430 |
+
{
|
| 431 |
+
"name": "Ghana",
|
| 432 |
+
"numeric3": "288",
|
| 433 |
+
"alpha2": "GH"
|
| 434 |
+
},
|
| 435 |
+
{
|
| 436 |
+
"name": "Gibraltar",
|
| 437 |
+
"numeric3": "292",
|
| 438 |
+
"alpha2": "GI"
|
| 439 |
+
},
|
| 440 |
+
{
|
| 441 |
+
"name": "Greece",
|
| 442 |
+
"numeric3": "300",
|
| 443 |
+
"alpha2": "GR"
|
| 444 |
+
},
|
| 445 |
+
{
|
| 446 |
+
"name": "Greenland",
|
| 447 |
+
"numeric3": "304",
|
| 448 |
+
"alpha2": "GL"
|
| 449 |
+
},
|
| 450 |
+
{
|
| 451 |
+
"name": "Grenada",
|
| 452 |
+
"numeric3": "308",
|
| 453 |
+
"alpha2": "GD"
|
| 454 |
+
},
|
| 455 |
+
{
|
| 456 |
+
"name": "Guadeloupe",
|
| 457 |
+
"numeric3": "312",
|
| 458 |
+
"alpha2": "GP"
|
| 459 |
+
},
|
| 460 |
+
{
|
| 461 |
+
"name": "Guam",
|
| 462 |
+
"numeric3": "316",
|
| 463 |
+
"alpha2": "GU"
|
| 464 |
+
},
|
| 465 |
+
{
|
| 466 |
+
"name": "Guatemala",
|
| 467 |
+
"numeric3": "320",
|
| 468 |
+
"alpha2": "GT"
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"name": "Guernsey",
|
| 472 |
+
"numeric3": "831",
|
| 473 |
+
"alpha2": "GG"
|
| 474 |
+
},
|
| 475 |
+
{
|
| 476 |
+
"name": "Guinea",
|
| 477 |
+
"numeric3": "324",
|
| 478 |
+
"alpha2": "GN"
|
| 479 |
+
},
|
| 480 |
+
{
|
| 481 |
+
"name": "Guinea-Bissau",
|
| 482 |
+
"numeric3": "624",
|
| 483 |
+
"alpha2": "GW"
|
| 484 |
+
},
|
| 485 |
+
{
|
| 486 |
+
"name": "Guyana",
|
| 487 |
+
"numeric3": "328",
|
| 488 |
+
"alpha2": "GY"
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"name": "Haiti",
|
| 492 |
+
"numeric3": "332",
|
| 493 |
+
"alpha2": "HT"
|
| 494 |
+
},
|
| 495 |
+
{
|
| 496 |
+
"name": "Heard Island and McDonald Islands",
|
| 497 |
+
"numeric3": "334",
|
| 498 |
+
"alpha2": "HM"
|
| 499 |
+
},
|
| 500 |
+
{
|
| 501 |
+
"name": "Holy See (the)",
|
| 502 |
+
"numeric3": "336",
|
| 503 |
+
"alpha2": "VA"
|
| 504 |
+
},
|
| 505 |
+
{
|
| 506 |
+
"name": "Honduras",
|
| 507 |
+
"numeric3": "340",
|
| 508 |
+
"alpha2": "HN"
|
| 509 |
+
},
|
| 510 |
+
{
|
| 511 |
+
"name": "Hong Kong",
|
| 512 |
+
"numeric3": "344",
|
| 513 |
+
"alpha2": "HK"
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
"name": "Hungary",
|
| 517 |
+
"numeric3": "348",
|
| 518 |
+
"alpha2": "HU"
|
| 519 |
+
},
|
| 520 |
+
{
|
| 521 |
+
"name": "Iceland",
|
| 522 |
+
"numeric3": "352",
|
| 523 |
+
"alpha2": "IS"
|
| 524 |
+
},
|
| 525 |
+
{
|
| 526 |
+
"name": "India",
|
| 527 |
+
"numeric3": "356",
|
| 528 |
+
"alpha2": "IN"
|
| 529 |
+
},
|
| 530 |
+
{
|
| 531 |
+
"name": "Indonesia",
|
| 532 |
+
"numeric3": "360",
|
| 533 |
+
"alpha2": "ID"
|
| 534 |
+
},
|
| 535 |
+
{
|
| 536 |
+
"name": "Iran (Islamic Republic of)",
|
| 537 |
+
"numeric3": "364",
|
| 538 |
+
"alpha2": "IR"
|
| 539 |
+
},
|
| 540 |
+
{
|
| 541 |
+
"name": "Iraq",
|
| 542 |
+
"numeric3": "368",
|
| 543 |
+
"alpha2": "IQ"
|
| 544 |
+
},
|
| 545 |
+
{
|
| 546 |
+
"name": "Ireland",
|
| 547 |
+
"numeric3": "372",
|
| 548 |
+
"alpha2": "IE"
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"name": "Isle of Man",
|
| 552 |
+
"numeric3": "833",
|
| 553 |
+
"alpha2": "IM"
|
| 554 |
+
},
|
| 555 |
+
{
|
| 556 |
+
"name": "Israel",
|
| 557 |
+
"numeric3": "376",
|
| 558 |
+
"alpha2": "IL"
|
| 559 |
+
},
|
| 560 |
+
{
|
| 561 |
+
"name": "Italy",
|
| 562 |
+
"numeric3": "380",
|
| 563 |
+
"alpha2": "IT"
|
| 564 |
+
},
|
| 565 |
+
{
|
| 566 |
+
"name": "Jamaica",
|
| 567 |
+
"numeric3": "388",
|
| 568 |
+
"alpha2": "JM"
|
| 569 |
+
},
|
| 570 |
+
{
|
| 571 |
+
"name": "Japan",
|
| 572 |
+
"numeric3": "392",
|
| 573 |
+
"alpha2": "JP"
|
| 574 |
+
},
|
| 575 |
+
{
|
| 576 |
+
"name": "Jersey",
|
| 577 |
+
"numeric3": "832",
|
| 578 |
+
"alpha2": "JE"
|
| 579 |
+
},
|
| 580 |
+
{
|
| 581 |
+
"name": "Jordan",
|
| 582 |
+
"numeric3": "400",
|
| 583 |
+
"alpha2": "JO"
|
| 584 |
+
},
|
| 585 |
+
{
|
| 586 |
+
"name": "Kazakhstan",
|
| 587 |
+
"numeric3": "398",
|
| 588 |
+
"alpha2": "KZ"
|
| 589 |
+
},
|
| 590 |
+
{
|
| 591 |
+
"name": "Kenya",
|
| 592 |
+
"numeric3": "404",
|
| 593 |
+
"alpha2": "KE"
|
| 594 |
+
},
|
| 595 |
+
{
|
| 596 |
+
"name": "Kiribati",
|
| 597 |
+
"numeric3": "296",
|
| 598 |
+
"alpha2": "KI"
|
| 599 |
+
},
|
| 600 |
+
{
|
| 601 |
+
"name": "Korea (the Democratic People's Republic of)",
|
| 602 |
+
"numeric3": "408",
|
| 603 |
+
"alpha2": "KP"
|
| 604 |
+
},
|
| 605 |
+
{
|
| 606 |
+
"name": "Korea (the Republic of)",
|
| 607 |
+
"numeric3": "410",
|
| 608 |
+
"alpha2": "KR"
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"name": "Kuwait",
|
| 612 |
+
"numeric3": "414",
|
| 613 |
+
"alpha2": "KW"
|
| 614 |
+
},
|
| 615 |
+
{
|
| 616 |
+
"name": "Kyrgyzstan",
|
| 617 |
+
"numeric3": "417",
|
| 618 |
+
"alpha2": "KG"
|
| 619 |
+
},
|
| 620 |
+
{
|
| 621 |
+
"name": "Lao People's Democratic Republic (the)",
|
| 622 |
+
"numeric3": "418",
|
| 623 |
+
"alpha2": "LA"
|
| 624 |
+
},
|
| 625 |
+
{
|
| 626 |
+
"name": "Latvia",
|
| 627 |
+
"numeric3": "428",
|
| 628 |
+
"alpha2": "LV"
|
| 629 |
+
},
|
| 630 |
+
{
|
| 631 |
+
"name": "Lebanon",
|
| 632 |
+
"numeric3": "422",
|
| 633 |
+
"alpha2": "LB"
|
| 634 |
+
},
|
| 635 |
+
{
|
| 636 |
+
"name": "Lesotho",
|
| 637 |
+
"numeric3": "426",
|
| 638 |
+
"alpha2": "LS"
|
| 639 |
+
},
|
| 640 |
+
{
|
| 641 |
+
"name": "Liberia",
|
| 642 |
+
"numeric3": "430",
|
| 643 |
+
"alpha2": "LR"
|
| 644 |
+
},
|
| 645 |
+
{
|
| 646 |
+
"name": "Libya",
|
| 647 |
+
"numeric3": "434",
|
| 648 |
+
"alpha2": "LY"
|
| 649 |
+
},
|
| 650 |
+
{
|
| 651 |
+
"name": "Liechtenstein",
|
| 652 |
+
"numeric3": "438",
|
| 653 |
+
"alpha2": "LI"
|
| 654 |
+
},
|
| 655 |
+
{
|
| 656 |
+
"name": "Lithuania",
|
| 657 |
+
"numeric3": "440",
|
| 658 |
+
"alpha2": "LT"
|
| 659 |
+
},
|
| 660 |
+
{
|
| 661 |
+
"name": "Luxembourg",
|
| 662 |
+
"numeric3": "442",
|
| 663 |
+
"alpha2": "LU"
|
| 664 |
+
},
|
| 665 |
+
{
|
| 666 |
+
"name": "Macao",
|
| 667 |
+
"numeric3": "446",
|
| 668 |
+
"alpha2": "MO"
|
| 669 |
+
},
|
| 670 |
+
{
|
| 671 |
+
"name": "North Macedonia",
|
| 672 |
+
"numeric3": "807",
|
| 673 |
+
"alpha2": "MK"
|
| 674 |
+
},
|
| 675 |
+
{
|
| 676 |
+
"name": "Madagascar",
|
| 677 |
+
"numeric3": "450",
|
| 678 |
+
"alpha2": "MG"
|
| 679 |
+
},
|
| 680 |
+
{
|
| 681 |
+
"name": "Malawi",
|
| 682 |
+
"numeric3": "454",
|
| 683 |
+
"alpha2": "MW"
|
| 684 |
+
},
|
| 685 |
+
{
|
| 686 |
+
"name": "Malaysia",
|
| 687 |
+
"numeric3": "458",
|
| 688 |
+
"alpha2": "MY"
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"name": "Maldives",
|
| 692 |
+
"numeric3": "462",
|
| 693 |
+
"alpha2": "MV"
|
| 694 |
+
},
|
| 695 |
+
{
|
| 696 |
+
"name": "Mali",
|
| 697 |
+
"numeric3": "466",
|
| 698 |
+
"alpha2": "ML"
|
| 699 |
+
},
|
| 700 |
+
{
|
| 701 |
+
"name": "Malta",
|
| 702 |
+
"numeric3": "470",
|
| 703 |
+
"alpha2": "MT"
|
| 704 |
+
},
|
| 705 |
+
{
|
| 706 |
+
"name": "Marshall Islands (the)",
|
| 707 |
+
"numeric3": "584",
|
| 708 |
+
"alpha2": "MH"
|
| 709 |
+
},
|
| 710 |
+
{
|
| 711 |
+
"name": "Martinique",
|
| 712 |
+
"numeric3": "474",
|
| 713 |
+
"alpha2": "MQ"
|
| 714 |
+
},
|
| 715 |
+
{
|
| 716 |
+
"name": "Mauritania",
|
| 717 |
+
"numeric3": "478",
|
| 718 |
+
"alpha2": "MR"
|
| 719 |
+
},
|
| 720 |
+
{
|
| 721 |
+
"name": "Mauritius",
|
| 722 |
+
"numeric3": "480",
|
| 723 |
+
"alpha2": "MU"
|
| 724 |
+
},
|
| 725 |
+
{
|
| 726 |
+
"name": "Mayotte",
|
| 727 |
+
"numeric3": "175",
|
| 728 |
+
"alpha2": "YT"
|
| 729 |
+
},
|
| 730 |
+
{
|
| 731 |
+
"name": "Mexico",
|
| 732 |
+
"numeric3": "484",
|
| 733 |
+
"alpha2": "MX"
|
| 734 |
+
},
|
| 735 |
+
{
|
| 736 |
+
"name": "Micronesia (Federated States of)",
|
| 737 |
+
"numeric3": "583",
|
| 738 |
+
"alpha2": "FM"
|
| 739 |
+
},
|
| 740 |
+
{
|
| 741 |
+
"name": "Moldova (the Republic of)",
|
| 742 |
+
"numeric3": "498",
|
| 743 |
+
"alpha2": "MD"
|
| 744 |
+
},
|
| 745 |
+
{
|
| 746 |
+
"name": "Monaco",
|
| 747 |
+
"numeric3": "492",
|
| 748 |
+
"alpha2": "MC"
|
| 749 |
+
},
|
| 750 |
+
{
|
| 751 |
+
"name": "Mongolia",
|
| 752 |
+
"numeric3": "496",
|
| 753 |
+
"alpha2": "MN"
|
| 754 |
+
},
|
| 755 |
+
{
|
| 756 |
+
"name": "Montenegro",
|
| 757 |
+
"numeric3": "499",
|
| 758 |
+
"alpha2": "ME"
|
| 759 |
+
},
|
| 760 |
+
{
|
| 761 |
+
"name": "Montserrat",
|
| 762 |
+
"numeric3": "500",
|
| 763 |
+
"alpha2": "MS"
|
| 764 |
+
},
|
| 765 |
+
{
|
| 766 |
+
"name": "Morocco",
|
| 767 |
+
"numeric3": "504",
|
| 768 |
+
"alpha2": "MA"
|
| 769 |
+
},
|
| 770 |
+
{
|
| 771 |
+
"name": "Mozambique",
|
| 772 |
+
"numeric3": "508",
|
| 773 |
+
"alpha2": "MZ"
|
| 774 |
+
},
|
| 775 |
+
{
|
| 776 |
+
"name": "Myanmar",
|
| 777 |
+
"numeric3": "104",
|
| 778 |
+
"alpha2": "MM"
|
| 779 |
+
},
|
| 780 |
+
{
|
| 781 |
+
"name": "Namibia",
|
| 782 |
+
"numeric3": "516",
|
| 783 |
+
"alpha2": "NA"
|
| 784 |
+
},
|
| 785 |
+
{
|
| 786 |
+
"name": "Nauru",
|
| 787 |
+
"numeric3": "520",
|
| 788 |
+
"alpha2": "NR"
|
| 789 |
+
},
|
| 790 |
+
{
|
| 791 |
+
"name": "Nepal",
|
| 792 |
+
"numeric3": "524",
|
| 793 |
+
"alpha2": "NP"
|
| 794 |
+
},
|
| 795 |
+
{
|
| 796 |
+
"name": "Netherlands (the)",
|
| 797 |
+
"numeric3": "528",
|
| 798 |
+
"alpha2": "NL"
|
| 799 |
+
},
|
| 800 |
+
{
|
| 801 |
+
"name": "New Caledonia",
|
| 802 |
+
"numeric3": "540",
|
| 803 |
+
"alpha2": "NC"
|
| 804 |
+
},
|
| 805 |
+
{
|
| 806 |
+
"name": "New Zealand",
|
| 807 |
+
"numeric3": "554",
|
| 808 |
+
"alpha2": "NZ"
|
| 809 |
+
},
|
| 810 |
+
{
|
| 811 |
+
"name": "Nicaragua",
|
| 812 |
+
"numeric3": "558",
|
| 813 |
+
"alpha2": "NI"
|
| 814 |
+
},
|
| 815 |
+
{
|
| 816 |
+
"name": "Niger (the)",
|
| 817 |
+
"numeric3": "562",
|
| 818 |
+
"alpha2": "NE"
|
| 819 |
+
},
|
| 820 |
+
{
|
| 821 |
+
"name": "Nigeria",
|
| 822 |
+
"numeric3": "566",
|
| 823 |
+
"alpha2": "NG"
|
| 824 |
+
},
|
| 825 |
+
{
|
| 826 |
+
"name": "Niue",
|
| 827 |
+
"numeric3": "570",
|
| 828 |
+
"alpha2": "NU"
|
| 829 |
+
},
|
| 830 |
+
{
|
| 831 |
+
"name": "Norfolk Island",
|
| 832 |
+
"numeric3": "574",
|
| 833 |
+
"alpha2": "NF"
|
| 834 |
+
},
|
| 835 |
+
{
|
| 836 |
+
"name": "Northern Mariana Islands (the)",
|
| 837 |
+
"numeric3": "580",
|
| 838 |
+
"alpha2": "MP"
|
| 839 |
+
},
|
| 840 |
+
{
|
| 841 |
+
"name": "Norway",
|
| 842 |
+
"numeric3": "578",
|
| 843 |
+
"alpha2": "NO"
|
| 844 |
+
},
|
| 845 |
+
{
|
| 846 |
+
"name": "Oman",
|
| 847 |
+
"numeric3": "512",
|
| 848 |
+
"alpha2": "OM"
|
| 849 |
+
},
|
| 850 |
+
{
|
| 851 |
+
"name": "Pakistan",
|
| 852 |
+
"numeric3": "586",
|
| 853 |
+
"alpha2": "PK"
|
| 854 |
+
},
|
| 855 |
+
{
|
| 856 |
+
"name": "Palau",
|
| 857 |
+
"numeric3": "585",
|
| 858 |
+
"alpha2": "PW"
|
| 859 |
+
},
|
| 860 |
+
{
|
| 861 |
+
"name": "Palestine, State of",
|
| 862 |
+
"numeric3": "275",
|
| 863 |
+
"alpha2": "PS"
|
| 864 |
+
},
|
| 865 |
+
{
|
| 866 |
+
"name": "Panama",
|
| 867 |
+
"numeric3": "591",
|
| 868 |
+
"alpha2": "PA"
|
| 869 |
+
},
|
| 870 |
+
{
|
| 871 |
+
"name": "Papua New Guinea",
|
| 872 |
+
"numeric3": "598",
|
| 873 |
+
"alpha2": "PG"
|
| 874 |
+
},
|
| 875 |
+
{
|
| 876 |
+
"name": "Paraguay",
|
| 877 |
+
"numeric3": "600",
|
| 878 |
+
"alpha2": "PY"
|
| 879 |
+
},
|
| 880 |
+
{
|
| 881 |
+
"name": "Peru",
|
| 882 |
+
"numeric3": "604",
|
| 883 |
+
"alpha2": "PE"
|
| 884 |
+
},
|
| 885 |
+
{
|
| 886 |
+
"name": "Philippines (the)",
|
| 887 |
+
"numeric3": "608",
|
| 888 |
+
"alpha2": "PH"
|
| 889 |
+
},
|
| 890 |
+
{
|
| 891 |
+
"name": "Pitcairn",
|
| 892 |
+
"numeric3": "612",
|
| 893 |
+
"alpha2": "PN"
|
| 894 |
+
},
|
| 895 |
+
{
|
| 896 |
+
"name": "Poland",
|
| 897 |
+
"numeric3": "616",
|
| 898 |
+
"alpha2": "PL"
|
| 899 |
+
},
|
| 900 |
+
{
|
| 901 |
+
"name": "Portugal",
|
| 902 |
+
"numeric3": "620",
|
| 903 |
+
"alpha2": "PT"
|
| 904 |
+
},
|
| 905 |
+
{
|
| 906 |
+
"name": "Puerto Rico",
|
| 907 |
+
"numeric3": "630",
|
| 908 |
+
"alpha2": "PR"
|
| 909 |
+
},
|
| 910 |
+
{
|
| 911 |
+
"name": "Qatar",
|
| 912 |
+
"numeric3": "634",
|
| 913 |
+
"alpha2": "QA"
|
| 914 |
+
},
|
| 915 |
+
{
|
| 916 |
+
"name": "Réunion",
|
| 917 |
+
"numeric3": "638",
|
| 918 |
+
"alpha2": "RE"
|
| 919 |
+
},
|
| 920 |
+
{
|
| 921 |
+
"name": "Romania",
|
| 922 |
+
"numeric3": "642",
|
| 923 |
+
"alpha2": "RO"
|
| 924 |
+
},
|
| 925 |
+
{
|
| 926 |
+
"name": "Russian Federation (the)",
|
| 927 |
+
"numeric3": "643",
|
| 928 |
+
"alpha2": "RU"
|
| 929 |
+
},
|
| 930 |
+
{
|
| 931 |
+
"name": "Rwanda",
|
| 932 |
+
"numeric3": "646",
|
| 933 |
+
"alpha2": "RW"
|
| 934 |
+
},
|
| 935 |
+
{
|
| 936 |
+
"name": "Saint Barthélemy",
|
| 937 |
+
"numeric3": "652",
|
| 938 |
+
"alpha2": "BL"
|
| 939 |
+
},
|
| 940 |
+
{
|
| 941 |
+
"name": "Saint Helena Ascension Island Tristan da Cunha",
|
| 942 |
+
"numeric3": "654",
|
| 943 |
+
"alpha2": "SH"
|
| 944 |
+
},
|
| 945 |
+
{
|
| 946 |
+
"name": "Saint Kitts and Nevis",
|
| 947 |
+
"numeric3": "659",
|
| 948 |
+
"alpha2": "KN"
|
| 949 |
+
},
|
| 950 |
+
{
|
| 951 |
+
"name": "Saint Lucia",
|
| 952 |
+
"numeric3": "662",
|
| 953 |
+
"alpha2": "LC"
|
| 954 |
+
},
|
| 955 |
+
{
|
| 956 |
+
"name": "Saint Martin (French part)",
|
| 957 |
+
"numeric3": "663",
|
| 958 |
+
"alpha2": "MF"
|
| 959 |
+
},
|
| 960 |
+
{
|
| 961 |
+
"name": "Saint Pierre and Miquelon",
|
| 962 |
+
"numeric3": "666",
|
| 963 |
+
"alpha2": "PM"
|
| 964 |
+
},
|
| 965 |
+
{
|
| 966 |
+
"name": "Saint Vincent and the Grenadines",
|
| 967 |
+
"numeric3": "670",
|
| 968 |
+
"alpha2": "VC"
|
| 969 |
+
},
|
| 970 |
+
{
|
| 971 |
+
"name": "Samoa",
|
| 972 |
+
"numeric3": "882",
|
| 973 |
+
"alpha2": "WS"
|
| 974 |
+
},
|
| 975 |
+
{
|
| 976 |
+
"name": "San Marino",
|
| 977 |
+
"numeric3": "674",
|
| 978 |
+
"alpha2": "SM"
|
| 979 |
+
},
|
| 980 |
+
{
|
| 981 |
+
"name": "Sao Tome and Principe",
|
| 982 |
+
"numeric3": "678",
|
| 983 |
+
"alpha2": "ST"
|
| 984 |
+
},
|
| 985 |
+
{
|
| 986 |
+
"name": "Saudi Arabia",
|
| 987 |
+
"numeric3": "682",
|
| 988 |
+
"alpha2": "SA"
|
| 989 |
+
},
|
| 990 |
+
{
|
| 991 |
+
"name": "Senegal",
|
| 992 |
+
"numeric3": "686",
|
| 993 |
+
"alpha2": "SN"
|
| 994 |
+
},
|
| 995 |
+
{
|
| 996 |
+
"name": "Serbia",
|
| 997 |
+
"numeric3": "688",
|
| 998 |
+
"alpha2": "RS"
|
| 999 |
+
},
|
| 1000 |
+
{
|
| 1001 |
+
"name": "Seychelles",
|
| 1002 |
+
"numeric3": "690",
|
| 1003 |
+
"alpha2": "SC"
|
| 1004 |
+
},
|
| 1005 |
+
{
|
| 1006 |
+
"name": "Sierra Leone",
|
| 1007 |
+
"numeric3": "694",
|
| 1008 |
+
"alpha2": "SL"
|
| 1009 |
+
},
|
| 1010 |
+
{
|
| 1011 |
+
"name": "Singapore",
|
| 1012 |
+
"numeric3": "702",
|
| 1013 |
+
"alpha2": "SG"
|
| 1014 |
+
},
|
| 1015 |
+
{
|
| 1016 |
+
"name": "Sint Maarten (Dutch part)",
|
| 1017 |
+
"numeric3": "534",
|
| 1018 |
+
"alpha2": "SX"
|
| 1019 |
+
},
|
| 1020 |
+
{
|
| 1021 |
+
"name": "Slovakia",
|
| 1022 |
+
"numeric3": "703",
|
| 1023 |
+
"alpha2": "SK"
|
| 1024 |
+
},
|
| 1025 |
+
{
|
| 1026 |
+
"name": "Slovenia",
|
| 1027 |
+
"numeric3": "705",
|
| 1028 |
+
"alpha2": "SI"
|
| 1029 |
+
},
|
| 1030 |
+
{
|
| 1031 |
+
"name": "Solomon Islands",
|
| 1032 |
+
"numeric3": "090",
|
| 1033 |
+
"alpha2": "SB"
|
| 1034 |
+
},
|
| 1035 |
+
{
|
| 1036 |
+
"name": "Somalia",
|
| 1037 |
+
"numeric3": "706",
|
| 1038 |
+
"alpha2": "SO"
|
| 1039 |
+
},
|
| 1040 |
+
{
|
| 1041 |
+
"name": "South Africa",
|
| 1042 |
+
"numeric3": "710",
|
| 1043 |
+
"alpha2": "ZA"
|
| 1044 |
+
},
|
| 1045 |
+
{
|
| 1046 |
+
"name": "South Georgia and the South Sandwich Islands",
|
| 1047 |
+
"numeric3": "239",
|
| 1048 |
+
"alpha2": "GS"
|
| 1049 |
+
},
|
| 1050 |
+
{
|
| 1051 |
+
"name": "South Sudan",
|
| 1052 |
+
"numeric3": "728",
|
| 1053 |
+
"alpha2": "SS"
|
| 1054 |
+
},
|
| 1055 |
+
{
|
| 1056 |
+
"name": "Spain",
|
| 1057 |
+
"numeric3": "724",
|
| 1058 |
+
"alpha2": "ES"
|
| 1059 |
+
},
|
| 1060 |
+
{
|
| 1061 |
+
"name": "Sri Lanka",
|
| 1062 |
+
"numeric3": "144",
|
| 1063 |
+
"alpha2": "LK"
|
| 1064 |
+
},
|
| 1065 |
+
{
|
| 1066 |
+
"name": "Sudan (the)",
|
| 1067 |
+
"numeric3": "729",
|
| 1068 |
+
"alpha2": "SD"
|
| 1069 |
+
},
|
| 1070 |
+
{
|
| 1071 |
+
"name": "Suriname",
|
| 1072 |
+
"numeric3": "740",
|
| 1073 |
+
"alpha2": "SR"
|
| 1074 |
+
},
|
| 1075 |
+
{
|
| 1076 |
+
"name": "Svalbard Jan Mayen",
|
| 1077 |
+
"numeric3": "744",
|
| 1078 |
+
"alpha2": "SJ"
|
| 1079 |
+
},
|
| 1080 |
+
{
|
| 1081 |
+
"name": "Sweden",
|
| 1082 |
+
"numeric3": "752",
|
| 1083 |
+
"alpha2": "SE"
|
| 1084 |
+
},
|
| 1085 |
+
{
|
| 1086 |
+
"name": "Switzerland",
|
| 1087 |
+
"numeric3": "756",
|
| 1088 |
+
"alpha2": "CH"
|
| 1089 |
+
},
|
| 1090 |
+
{
|
| 1091 |
+
"name": "Syrian Arab Republic (the)",
|
| 1092 |
+
"numeric3": "760",
|
| 1093 |
+
"alpha2": "SY"
|
| 1094 |
+
},
|
| 1095 |
+
{
|
| 1096 |
+
"name": "Taiwan (Province of China)",
|
| 1097 |
+
"numeric3": "158",
|
| 1098 |
+
"alpha2": "TW"
|
| 1099 |
+
},
|
| 1100 |
+
{
|
| 1101 |
+
"name": "Tajikistan",
|
| 1102 |
+
"numeric3": "762",
|
| 1103 |
+
"alpha2": "TJ"
|
| 1104 |
+
},
|
| 1105 |
+
{
|
| 1106 |
+
"name": "Tanzania, the United Republic of",
|
| 1107 |
+
"numeric3": "834",
|
| 1108 |
+
"alpha2": "TZ"
|
| 1109 |
+
},
|
| 1110 |
+
{
|
| 1111 |
+
"name": "Thailand",
|
| 1112 |
+
"numeric3": "764",
|
| 1113 |
+
"alpha2": "TH"
|
| 1114 |
+
},
|
| 1115 |
+
{
|
| 1116 |
+
"name": "Timor-Leste",
|
| 1117 |
+
"numeric3": "626",
|
| 1118 |
+
"alpha2": "TL"
|
| 1119 |
+
},
|
| 1120 |
+
{
|
| 1121 |
+
"name": "Togo",
|
| 1122 |
+
"numeric3": "768",
|
| 1123 |
+
"alpha2": "TG"
|
| 1124 |
+
},
|
| 1125 |
+
{
|
| 1126 |
+
"name": "Tokelau",
|
| 1127 |
+
"numeric3": "772",
|
| 1128 |
+
"alpha2": "TK"
|
| 1129 |
+
},
|
| 1130 |
+
{
|
| 1131 |
+
"name": "Tonga",
|
| 1132 |
+
"numeric3": "776",
|
| 1133 |
+
"alpha2": "TO"
|
| 1134 |
+
},
|
| 1135 |
+
{
|
| 1136 |
+
"name": "Trinidad and Tobago",
|
| 1137 |
+
"numeric3": "780",
|
| 1138 |
+
"alpha2": "TT"
|
| 1139 |
+
},
|
| 1140 |
+
{
|
| 1141 |
+
"name": "Tunisia",
|
| 1142 |
+
"numeric3": "788",
|
| 1143 |
+
"alpha2": "TN"
|
| 1144 |
+
},
|
| 1145 |
+
{
|
| 1146 |
+
"name": "Turkey",
|
| 1147 |
+
"numeric3": "792",
|
| 1148 |
+
"alpha2": "TR"
|
| 1149 |
+
},
|
| 1150 |
+
{
|
| 1151 |
+
"name": "Turkmenistan",
|
| 1152 |
+
"numeric3": "795",
|
| 1153 |
+
"alpha2": "TM"
|
| 1154 |
+
},
|
| 1155 |
+
{
|
| 1156 |
+
"name": "Turks and Caicos Islands (the)",
|
| 1157 |
+
"numeric3": "796",
|
| 1158 |
+
"alpha2": "TC"
|
| 1159 |
+
},
|
| 1160 |
+
{
|
| 1161 |
+
"name": "Tuvalu",
|
| 1162 |
+
"numeric3": "798",
|
| 1163 |
+
"alpha2": "TV"
|
| 1164 |
+
},
|
| 1165 |
+
{
|
| 1166 |
+
"name": "Uganda",
|
| 1167 |
+
"numeric3": "800",
|
| 1168 |
+
"alpha2": "UG"
|
| 1169 |
+
},
|
| 1170 |
+
{
|
| 1171 |
+
"name": "Ukraine",
|
| 1172 |
+
"numeric3": "804",
|
| 1173 |
+
"alpha2": "UA"
|
| 1174 |
+
},
|
| 1175 |
+
{
|
| 1176 |
+
"name": "United Arab Emirates (the)",
|
| 1177 |
+
"numeric3": "784",
|
| 1178 |
+
"alpha2": "AE"
|
| 1179 |
+
},
|
| 1180 |
+
{
|
| 1181 |
+
"name": "United Kingdom of Great Britain and Northern Ireland (the)",
|
| 1182 |
+
"numeric3": "826",
|
| 1183 |
+
"alpha2": "GB"
|
| 1184 |
+
},
|
| 1185 |
+
{
|
| 1186 |
+
"name": "United States Minor Outlying Islands (the)",
|
| 1187 |
+
"numeric3": "581",
|
| 1188 |
+
"alpha2": "UM"
|
| 1189 |
+
},
|
| 1190 |
+
{
|
| 1191 |
+
"name": "United States of America (the)",
|
| 1192 |
+
"numeric3": "840",
|
| 1193 |
+
"alpha2": "US"
|
| 1194 |
+
},
|
| 1195 |
+
{
|
| 1196 |
+
"name": "Uruguay",
|
| 1197 |
+
"numeric3": "858",
|
| 1198 |
+
"alpha2": "UY"
|
| 1199 |
+
},
|
| 1200 |
+
{
|
| 1201 |
+
"name": "Uzbekistan",
|
| 1202 |
+
"numeric3": "860",
|
| 1203 |
+
"alpha2": "UZ"
|
| 1204 |
+
},
|
| 1205 |
+
{
|
| 1206 |
+
"name": "Vanuatu",
|
| 1207 |
+
"numeric3": "548",
|
| 1208 |
+
"alpha2": "VU"
|
| 1209 |
+
},
|
| 1210 |
+
{
|
| 1211 |
+
"name": "Venezuela (Bolivarian Republic of)",
|
| 1212 |
+
"numeric3": "862",
|
| 1213 |
+
"alpha2": "VE"
|
| 1214 |
+
},
|
| 1215 |
+
{
|
| 1216 |
+
"name": "Viet Nam",
|
| 1217 |
+
"numeric3": "704",
|
| 1218 |
+
"alpha2": "VN"
|
| 1219 |
+
},
|
| 1220 |
+
{
|
| 1221 |
+
"name": "Virgin Islands (British)",
|
| 1222 |
+
"numeric3": "092",
|
| 1223 |
+
"alpha2": "VG"
|
| 1224 |
+
},
|
| 1225 |
+
{
|
| 1226 |
+
"name": "Virgin Islands (U.S.)",
|
| 1227 |
+
"numeric3": "850",
|
| 1228 |
+
"alpha2": "VI"
|
| 1229 |
+
},
|
| 1230 |
+
{
|
| 1231 |
+
"name": "Wallis and Futuna",
|
| 1232 |
+
"numeric3": "876",
|
| 1233 |
+
"alpha2": "WF"
|
| 1234 |
+
},
|
| 1235 |
+
{
|
| 1236 |
+
"name": "Western Sahara",
|
| 1237 |
+
"numeric3": "732",
|
| 1238 |
+
"alpha2": "EH"
|
| 1239 |
+
},
|
| 1240 |
+
{
|
| 1241 |
+
"name": "Yemen",
|
| 1242 |
+
"numeric3": "887",
|
| 1243 |
+
"alpha2": "YE"
|
| 1244 |
+
},
|
| 1245 |
+
{
|
| 1246 |
+
"name": "Zambia",
|
| 1247 |
+
"numeric3": "894",
|
| 1248 |
+
"alpha2": "ZM"
|
| 1249 |
+
},
|
| 1250 |
+
{
|
| 1251 |
+
"name": "Zimbabwe",
|
| 1252 |
+
"numeric3": "716",
|
| 1253 |
+
"alpha2": "ZW"
|
| 1254 |
+
}
|
| 1255 |
+
];
|
| 1256 |
+
|
| 1257 |
+
return {
|
| 1258 |
+
/**
|
| 1259 |
+
* @param code country code corresponding to alpha2, alpha3 or numeric3
|
| 1260 |
+
* @returns {alpha2: String, numeric3: String, name: String}
|
| 1261 |
+
*/
|
| 1262 |
+
lookup: function (code) {
|
| 1263 |
+
if (!code) {
|
| 1264 |
+
return;
|
| 1265 |
+
}
|
| 1266 |
+
for (let i = 0; i < codes.length; i++) {
|
| 1267 |
+
const codeMap = codes[i];
|
| 1268 |
+
if (String(code).toUpperCase() === codeMap.alpha2 || Number(code) === Number(codeMap.numeric3)) {
|
| 1269 |
+
return codeMap;
|
| 1270 |
+
}
|
| 1271 |
+
}
|
| 1272 |
+
},
|
| 1273 |
+
codes: codes
|
| 1274 |
+
}
|
| 1275 |
+
}());
|
js/iso-639-translator.js
ADDED
|
@@ -0,0 +1,2362 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Implementation to quickly translate ISO 639 language codes.
|
| 3 |
+
*
|
| 4 |
+
* Combination of sources
|
| 5 |
+
* @link https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
| 6 |
+
* @link https://www.loc.gov/standards/iso639-2/php/code_list.php
|
| 7 |
+
*/
|
| 8 |
+
const iso639 = (function () {
|
| 9 |
+
'use strict';
|
| 10 |
+
|
| 11 |
+
const codes = [
|
| 12 |
+
{
|
| 13 |
+
"639_1": "aa",
|
| 14 |
+
"639_2_T": "aar",
|
| 15 |
+
"639_2_B": "aar",
|
| 16 |
+
"name": "Afar"
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"639_1": "ab",
|
| 20 |
+
"639_2_T": "abk",
|
| 21 |
+
"639_2_B": "abk",
|
| 22 |
+
"name": "Abkhazian"
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"639_2_T": "ace",
|
| 26 |
+
"name": "Achinese"
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"639_2_T": "ach",
|
| 30 |
+
"name": "Acoli"
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"639_2_T": "ada",
|
| 34 |
+
"name": "Adangme"
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"639_2_T": "ady",
|
| 38 |
+
"name": "Adyghe; Adygei"
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"639_2_T": "afa",
|
| 42 |
+
"name": "Afro-Asiatic languages"
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"639_2_T": "afh",
|
| 46 |
+
"name": "Afrihili"
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"639_1": "af",
|
| 50 |
+
"639_2_T": "afr",
|
| 51 |
+
"639_2_B": "afr",
|
| 52 |
+
"name": "Afrikaans"
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"639_2_T": "ain",
|
| 56 |
+
"name": "Ainu"
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"639_1": "ak",
|
| 60 |
+
"639_2_T": "aka",
|
| 61 |
+
"639_2_B": "aka",
|
| 62 |
+
"name": "Akan"
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"639_2_T": "akk",
|
| 66 |
+
"name": "Akkadian"
|
| 67 |
+
},
|
| 68 |
+
{
|
| 69 |
+
"639_2_T": "ale",
|
| 70 |
+
"name": "Aleut"
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"639_2_T": "alg",
|
| 74 |
+
"name": "Algonquian languages"
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"639_2_T": "alt",
|
| 78 |
+
"name": "Southern Altai"
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"639_1": "am",
|
| 82 |
+
"639_2_T": "amh",
|
| 83 |
+
"639_2_B": "amh",
|
| 84 |
+
"name": "Amharic"
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"639_2_T": "ang",
|
| 88 |
+
"name": "English, Old (ca.450-1100)"
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"639_2_T": "anp",
|
| 92 |
+
"name": "Angika"
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"639_2_T": "apa",
|
| 96 |
+
"name": "Apache languages"
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"639_1": "ar",
|
| 100 |
+
"639_2_T": "ara",
|
| 101 |
+
"639_2_B": "ara",
|
| 102 |
+
"name": "Arabic"
|
| 103 |
+
},
|
| 104 |
+
{
|
| 105 |
+
"639_2_T": "arc",
|
| 106 |
+
"name": "Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)"
|
| 107 |
+
},
|
| 108 |
+
{
|
| 109 |
+
"639_1": "an",
|
| 110 |
+
"639_2_T": "arg",
|
| 111 |
+
"639_2_B": "arg",
|
| 112 |
+
"name": "Aragonese"
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"639_2_T": "arn",
|
| 116 |
+
"name": "Mapudungun; Mapuche"
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"639_2_T": "arp",
|
| 120 |
+
"name": "Arapaho"
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"639_2_T": "art",
|
| 124 |
+
"name": "Artificial languages"
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"639_2_T": "arw",
|
| 128 |
+
"name": "Arawak"
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"639_1": "as",
|
| 132 |
+
"639_2_T": "asm",
|
| 133 |
+
"639_2_B": "asm",
|
| 134 |
+
"name": "Assamese"
|
| 135 |
+
},
|
| 136 |
+
{
|
| 137 |
+
"639_2_T": "ast",
|
| 138 |
+
"name": "Asturian; Bable; Leonese; Asturleonese"
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"639_2_T": "ath",
|
| 142 |
+
"name": "Athapascan languages"
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
"639_2_T": "aus",
|
| 146 |
+
"name": "Australian languages"
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"639_1": "av",
|
| 150 |
+
"639_2_T": "ava",
|
| 151 |
+
"639_2_B": "ava",
|
| 152 |
+
"name": "Avaric"
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"639_1": "ae",
|
| 156 |
+
"639_2_T": "ave",
|
| 157 |
+
"639_2_B": "ave",
|
| 158 |
+
"name": "Avestan"
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"639_2_T": "awa",
|
| 162 |
+
"name": "Awadhi"
|
| 163 |
+
},
|
| 164 |
+
{
|
| 165 |
+
"639_1": "ay",
|
| 166 |
+
"639_2_T": "aym",
|
| 167 |
+
"639_2_B": "aym",
|
| 168 |
+
"name": "Aymara"
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"639_1": "az",
|
| 172 |
+
"639_2_T": "aze",
|
| 173 |
+
"639_2_B": "aze",
|
| 174 |
+
"name": "Azerbaijani"
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"639_2_T": "bad",
|
| 178 |
+
"name": "Banda languages"
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
"639_2_T": "bai",
|
| 182 |
+
"name": "Bamileke languages"
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"639_1": "ba",
|
| 186 |
+
"639_2_T": "bak",
|
| 187 |
+
"639_2_B": "bak",
|
| 188 |
+
"name": "Bashkir"
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"639_2_T": "bal",
|
| 192 |
+
"name": "Baluchi"
|
| 193 |
+
},
|
| 194 |
+
{
|
| 195 |
+
"639_1": "bm",
|
| 196 |
+
"639_2_T": "bam",
|
| 197 |
+
"639_2_B": "bam",
|
| 198 |
+
"name": "Bambara"
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"639_2_T": "ban",
|
| 202 |
+
"name": "Balinese"
|
| 203 |
+
},
|
| 204 |
+
{
|
| 205 |
+
"639_2_T": "bas",
|
| 206 |
+
"name": "Basa"
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"639_2_T": "bat",
|
| 210 |
+
"name": "Baltic languages"
|
| 211 |
+
},
|
| 212 |
+
{
|
| 213 |
+
"639_2_T": "bej",
|
| 214 |
+
"name": "Beja; Bedawiyet"
|
| 215 |
+
},
|
| 216 |
+
{
|
| 217 |
+
"639_1": "be",
|
| 218 |
+
"639_2_T": "bel",
|
| 219 |
+
"639_2_B": "bel",
|
| 220 |
+
"name": "Belarusian"
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"639_2_T": "bem",
|
| 224 |
+
"name": "Bemba"
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"639_1": "bn",
|
| 228 |
+
"639_2_T": "ben",
|
| 229 |
+
"639_2_B": "ben",
|
| 230 |
+
"name": "Bengali"
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"639_2_T": "ber",
|
| 234 |
+
"name": "Berber languages"
|
| 235 |
+
},
|
| 236 |
+
{
|
| 237 |
+
"639_2_T": "bho",
|
| 238 |
+
"name": "Bhojpuri"
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"639_1": "bh",
|
| 242 |
+
"639_2_T": "bih",
|
| 243 |
+
"639_2_B": "bih",
|
| 244 |
+
"name": "Bihari languages"
|
| 245 |
+
},
|
| 246 |
+
{
|
| 247 |
+
"639_2_T": "bik",
|
| 248 |
+
"name": "Bikol"
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"639_2_T": "bin",
|
| 252 |
+
"name": "Bini; Edo"
|
| 253 |
+
},
|
| 254 |
+
{
|
| 255 |
+
"639_1": "bi",
|
| 256 |
+
"639_2_T": "bis",
|
| 257 |
+
"639_2_B": "bis",
|
| 258 |
+
"name": "Bislama"
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
"639_2_T": "bla",
|
| 262 |
+
"name": "Siksika"
|
| 263 |
+
},
|
| 264 |
+
{
|
| 265 |
+
"639_2_T": "bnt",
|
| 266 |
+
"name": "Bantu languages"
|
| 267 |
+
},
|
| 268 |
+
{
|
| 269 |
+
"639_1": "bo",
|
| 270 |
+
"639_2_T": "bod",
|
| 271 |
+
"639_2_B": "tib",
|
| 272 |
+
"name": "Tibetan"
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"639_1": "bs",
|
| 276 |
+
"639_2_T": "bos",
|
| 277 |
+
"639_2_B": "bos",
|
| 278 |
+
"name": "Bosnian"
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"639_2_T": "bra",
|
| 282 |
+
"name": "Braj"
|
| 283 |
+
},
|
| 284 |
+
{
|
| 285 |
+
"639_1": "br",
|
| 286 |
+
"639_2_T": "bre",
|
| 287 |
+
"639_2_B": "bre",
|
| 288 |
+
"name": "Breton"
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"639_2_T": "btk",
|
| 292 |
+
"name": "Batak languages"
|
| 293 |
+
},
|
| 294 |
+
{
|
| 295 |
+
"639_2_T": "bua",
|
| 296 |
+
"name": "Buriat"
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"639_2_T": "bug",
|
| 300 |
+
"name": "Buginese"
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"639_1": "bg",
|
| 304 |
+
"639_2_T": "bul",
|
| 305 |
+
"639_2_B": "bul",
|
| 306 |
+
"name": "Bulgarian"
|
| 307 |
+
},
|
| 308 |
+
{
|
| 309 |
+
"639_2_T": "byn",
|
| 310 |
+
"name": "Blin; Bilin"
|
| 311 |
+
},
|
| 312 |
+
{
|
| 313 |
+
"639_2_T": "cad",
|
| 314 |
+
"name": "Caddo"
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"639_2_T": "cai",
|
| 318 |
+
"name": "Central American Indian languages"
|
| 319 |
+
},
|
| 320 |
+
{
|
| 321 |
+
"639_2_T": "car",
|
| 322 |
+
"name": "Galibi Carib"
|
| 323 |
+
},
|
| 324 |
+
{
|
| 325 |
+
"639_1": "ca",
|
| 326 |
+
"639_2_T": "cat",
|
| 327 |
+
"639_2_B": "cat",
|
| 328 |
+
"name": "Catalan, Valencian"
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"639_2_T": "cau",
|
| 332 |
+
"name": "Caucasian languages"
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"639_2_T": "ceb",
|
| 336 |
+
"name": "Cebuano"
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"639_2_T": "cel",
|
| 340 |
+
"name": "Celtic languages"
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"639_1": "cs",
|
| 344 |
+
"639_2_T": "ces",
|
| 345 |
+
"639_2_B": "cze",
|
| 346 |
+
"name": "Czech"
|
| 347 |
+
},
|
| 348 |
+
{
|
| 349 |
+
"639_1": "ch",
|
| 350 |
+
"639_2_T": "cha",
|
| 351 |
+
"639_2_B": "cha",
|
| 352 |
+
"name": "Chamorro"
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"639_2_T": "chb",
|
| 356 |
+
"name": "Chibcha"
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"639_1": "ce",
|
| 360 |
+
"639_2_T": "che",
|
| 361 |
+
"639_2_B": "che",
|
| 362 |
+
"name": "Chechen"
|
| 363 |
+
},
|
| 364 |
+
{
|
| 365 |
+
"639_2_T": "chg",
|
| 366 |
+
"name": "Chagatai"
|
| 367 |
+
},
|
| 368 |
+
{
|
| 369 |
+
"639_2_T": "chk",
|
| 370 |
+
"name": "Chuukese"
|
| 371 |
+
},
|
| 372 |
+
{
|
| 373 |
+
"639_2_T": "chm",
|
| 374 |
+
"name": "Mari"
|
| 375 |
+
},
|
| 376 |
+
{
|
| 377 |
+
"639_2_T": "chn",
|
| 378 |
+
"name": "Chinook jargon"
|
| 379 |
+
},
|
| 380 |
+
{
|
| 381 |
+
"639_2_T": "cho",
|
| 382 |
+
"name": "Choctaw"
|
| 383 |
+
},
|
| 384 |
+
{
|
| 385 |
+
"639_2_T": "chp",
|
| 386 |
+
"name": "Chipewyan; Dene Suline"
|
| 387 |
+
},
|
| 388 |
+
{
|
| 389 |
+
"639_2_T": "chr",
|
| 390 |
+
"name": "Cherokee"
|
| 391 |
+
},
|
| 392 |
+
{
|
| 393 |
+
"639_1": "cu",
|
| 394 |
+
"639_2_T": "chu",
|
| 395 |
+
"639_2_B": "chu",
|
| 396 |
+
"name": "Church Slavic, Old Slavonic, Church Slavonic, Old Bulgarian, Old Church Slavonic"
|
| 397 |
+
},
|
| 398 |
+
{
|
| 399 |
+
"639_1": "cv",
|
| 400 |
+
"639_2_T": "chv",
|
| 401 |
+
"639_2_B": "chv",
|
| 402 |
+
"name": "Chuvash"
|
| 403 |
+
},
|
| 404 |
+
{
|
| 405 |
+
"639_2_T": "chy",
|
| 406 |
+
"name": "Cheyenne"
|
| 407 |
+
},
|
| 408 |
+
{
|
| 409 |
+
"639_2_T": "cmc",
|
| 410 |
+
"name": "Chamic languages"
|
| 411 |
+
},
|
| 412 |
+
{
|
| 413 |
+
"639_2_T": "cnr",
|
| 414 |
+
"name": "Montenegrin"
|
| 415 |
+
},
|
| 416 |
+
{
|
| 417 |
+
"639_2_T": "cop",
|
| 418 |
+
"name": "Coptic"
|
| 419 |
+
},
|
| 420 |
+
{
|
| 421 |
+
"639_1": "kw",
|
| 422 |
+
"639_2_T": "cor",
|
| 423 |
+
"639_2_B": "cor",
|
| 424 |
+
"name": "Cornish"
|
| 425 |
+
},
|
| 426 |
+
{
|
| 427 |
+
"639_1": "co",
|
| 428 |
+
"639_2_T": "cos",
|
| 429 |
+
"639_2_B": "cos",
|
| 430 |
+
"name": "Corsican"
|
| 431 |
+
},
|
| 432 |
+
{
|
| 433 |
+
"639_2_T": "cpe",
|
| 434 |
+
"name": "Creoles and pidgins, English based"
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"639_2_T": "cpf",
|
| 438 |
+
"name": "Creoles and pidgins, French-based"
|
| 439 |
+
},
|
| 440 |
+
{
|
| 441 |
+
"639_2_T": "cpp",
|
| 442 |
+
"name": "Creoles and pidgins, Portuguese-based"
|
| 443 |
+
},
|
| 444 |
+
{
|
| 445 |
+
"639_1": "cr",
|
| 446 |
+
"639_2_T": "cre",
|
| 447 |
+
"639_2_B": "cre",
|
| 448 |
+
"name": "Cree"
|
| 449 |
+
},
|
| 450 |
+
{
|
| 451 |
+
"639_2_T": "crh",
|
| 452 |
+
"name": "Crimean Tatar; Crimean Turkish"
|
| 453 |
+
},
|
| 454 |
+
{
|
| 455 |
+
"639_2_T": "crp",
|
| 456 |
+
"name": "Creoles and pidgins"
|
| 457 |
+
},
|
| 458 |
+
{
|
| 459 |
+
"639_2_T": "csb",
|
| 460 |
+
"name": "Kashubian"
|
| 461 |
+
},
|
| 462 |
+
{
|
| 463 |
+
"639_2_T": "cus",
|
| 464 |
+
"name": "Cushitic languages"
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"639_1": "cy",
|
| 468 |
+
"639_2_T": "cym",
|
| 469 |
+
"639_2_B": "wel",
|
| 470 |
+
"name": "Welsh"
|
| 471 |
+
},
|
| 472 |
+
{
|
| 473 |
+
"639_2_T": "dak",
|
| 474 |
+
"name": "Dakota"
|
| 475 |
+
},
|
| 476 |
+
{
|
| 477 |
+
"639_1": "da",
|
| 478 |
+
"639_2_T": "dan",
|
| 479 |
+
"639_2_B": "dan",
|
| 480 |
+
"name": "Danish"
|
| 481 |
+
},
|
| 482 |
+
{
|
| 483 |
+
"639_2_T": "dar",
|
| 484 |
+
"name": "Dargwa"
|
| 485 |
+
},
|
| 486 |
+
{
|
| 487 |
+
"639_2_T": "day",
|
| 488 |
+
"name": "Land Dayak languages"
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"639_2_T": "del",
|
| 492 |
+
"name": "Delaware"
|
| 493 |
+
},
|
| 494 |
+
{
|
| 495 |
+
"639_2_T": "den",
|
| 496 |
+
"name": "Slave (Athapascan)"
|
| 497 |
+
},
|
| 498 |
+
{
|
| 499 |
+
"639_1": "de",
|
| 500 |
+
"639_2_T": "deu",
|
| 501 |
+
"639_2_B": "ger",
|
| 502 |
+
"name": "German"
|
| 503 |
+
},
|
| 504 |
+
{
|
| 505 |
+
"639_2_T": "dgr",
|
| 506 |
+
"name": "Dogrib"
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"639_2_T": "din",
|
| 510 |
+
"name": "Dinka"
|
| 511 |
+
},
|
| 512 |
+
{
|
| 513 |
+
"639_1": "dv",
|
| 514 |
+
"639_2_T": "div",
|
| 515 |
+
"639_2_B": "div",
|
| 516 |
+
"name": "Divehi, Dhivehi, Maldivian"
|
| 517 |
+
},
|
| 518 |
+
{
|
| 519 |
+
"639_2_T": "doi",
|
| 520 |
+
"name": "Dogri"
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"639_2_T": "dra",
|
| 524 |
+
"name": "Dravidian languages"
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"639_2_T": "dsb",
|
| 528 |
+
"name": "Lower Sorbian"
|
| 529 |
+
},
|
| 530 |
+
{
|
| 531 |
+
"639_2_T": "dua",
|
| 532 |
+
"name": "Duala"
|
| 533 |
+
},
|
| 534 |
+
{
|
| 535 |
+
"639_2_T": "dum",
|
| 536 |
+
"name": "Dutch, Middle (ca.1050-1350)"
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"639_2_T": "dyu",
|
| 540 |
+
"name": "Dyula"
|
| 541 |
+
},
|
| 542 |
+
{
|
| 543 |
+
"639_1": "dz",
|
| 544 |
+
"639_2_T": "dzo",
|
| 545 |
+
"639_2_B": "dzo",
|
| 546 |
+
"name": "Dzongkha"
|
| 547 |
+
},
|
| 548 |
+
{
|
| 549 |
+
"639_2_T": "efi",
|
| 550 |
+
"name": "Efik"
|
| 551 |
+
},
|
| 552 |
+
{
|
| 553 |
+
"639_2_T": "egy",
|
| 554 |
+
"name": "Egyptian (Ancient)"
|
| 555 |
+
},
|
| 556 |
+
{
|
| 557 |
+
"639_2_T": "eka",
|
| 558 |
+
"name": "Ekajuk"
|
| 559 |
+
},
|
| 560 |
+
{
|
| 561 |
+
"639_1": "el",
|
| 562 |
+
"639_2_T": "ell",
|
| 563 |
+
"639_2_B": "gre",
|
| 564 |
+
"name": "Greek, Modern (1453-)"
|
| 565 |
+
},
|
| 566 |
+
{
|
| 567 |
+
"639_2_T": "elx",
|
| 568 |
+
"name": "Elamite"
|
| 569 |
+
},
|
| 570 |
+
{
|
| 571 |
+
"639_1": "en",
|
| 572 |
+
"639_2_T": "eng",
|
| 573 |
+
"639_2_B": "eng",
|
| 574 |
+
"name": "English"
|
| 575 |
+
},
|
| 576 |
+
{
|
| 577 |
+
"639_2_T": "enm",
|
| 578 |
+
"name": "English, Middle (1100-1500)"
|
| 579 |
+
},
|
| 580 |
+
{
|
| 581 |
+
"639_1": "eo",
|
| 582 |
+
"639_2_T": "epo",
|
| 583 |
+
"639_2_B": "epo",
|
| 584 |
+
"name": "Esperanto"
|
| 585 |
+
},
|
| 586 |
+
{
|
| 587 |
+
"639_1": "et",
|
| 588 |
+
"639_2_T": "est",
|
| 589 |
+
"639_2_B": "est",
|
| 590 |
+
"name": "Estonian"
|
| 591 |
+
},
|
| 592 |
+
{
|
| 593 |
+
"639_1": "eu",
|
| 594 |
+
"639_2_T": "eus",
|
| 595 |
+
"639_2_B": "baq",
|
| 596 |
+
"name": "Basque"
|
| 597 |
+
},
|
| 598 |
+
{
|
| 599 |
+
"639_1": "ee",
|
| 600 |
+
"639_2_T": "ewe",
|
| 601 |
+
"639_2_B": "ewe",
|
| 602 |
+
"name": "Ewe"
|
| 603 |
+
},
|
| 604 |
+
{
|
| 605 |
+
"639_2_T": "ewo",
|
| 606 |
+
"name": "Ewondo"
|
| 607 |
+
},
|
| 608 |
+
{
|
| 609 |
+
"639_2_T": "fan",
|
| 610 |
+
"name": "Fang"
|
| 611 |
+
},
|
| 612 |
+
{
|
| 613 |
+
"639_1": "fo",
|
| 614 |
+
"639_2_T": "fao",
|
| 615 |
+
"639_2_B": "fao",
|
| 616 |
+
"name": "Faroese"
|
| 617 |
+
},
|
| 618 |
+
{
|
| 619 |
+
"639_1": "fa",
|
| 620 |
+
"639_2_T": "fas",
|
| 621 |
+
"639_2_B": "per",
|
| 622 |
+
"name": "Persian"
|
| 623 |
+
},
|
| 624 |
+
{
|
| 625 |
+
"639_2_T": "fat",
|
| 626 |
+
"name": "Fanti"
|
| 627 |
+
},
|
| 628 |
+
{
|
| 629 |
+
"639_1": "fj",
|
| 630 |
+
"639_2_T": "fij",
|
| 631 |
+
"639_2_B": "fij",
|
| 632 |
+
"name": "Fijian"
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"639_2_T": "fil",
|
| 636 |
+
"name": "Filipino; Pilipino"
|
| 637 |
+
},
|
| 638 |
+
{
|
| 639 |
+
"639_1": "fi",
|
| 640 |
+
"639_2_T": "fin",
|
| 641 |
+
"639_2_B": "fin",
|
| 642 |
+
"name": "Finnish"
|
| 643 |
+
},
|
| 644 |
+
{
|
| 645 |
+
"639_2_T": "fiu",
|
| 646 |
+
"name": "Finno-Ugrian languages"
|
| 647 |
+
},
|
| 648 |
+
{
|
| 649 |
+
"639_2_T": "fon",
|
| 650 |
+
"name": "Fon"
|
| 651 |
+
},
|
| 652 |
+
{
|
| 653 |
+
"639_1": "fr",
|
| 654 |
+
"639_2_T": "fra",
|
| 655 |
+
"639_2_B": "fre",
|
| 656 |
+
"name": "French"
|
| 657 |
+
},
|
| 658 |
+
{
|
| 659 |
+
"639_2_T": "frm",
|
| 660 |
+
"name": "French, Middle (ca.1400-1600)"
|
| 661 |
+
},
|
| 662 |
+
{
|
| 663 |
+
"639_2_T": "fro",
|
| 664 |
+
"name": "French, Old (842-ca.1400)"
|
| 665 |
+
},
|
| 666 |
+
{
|
| 667 |
+
"639_2_T": "frr",
|
| 668 |
+
"name": "Northern Frisian"
|
| 669 |
+
},
|
| 670 |
+
{
|
| 671 |
+
"639_2_T": "frs",
|
| 672 |
+
"name": "Eastern Frisian"
|
| 673 |
+
},
|
| 674 |
+
{
|
| 675 |
+
"639_1": "fy",
|
| 676 |
+
"639_2_T": "fry",
|
| 677 |
+
"639_2_B": "fry",
|
| 678 |
+
"name": "Western Frisian"
|
| 679 |
+
},
|
| 680 |
+
{
|
| 681 |
+
"639_1": "ff",
|
| 682 |
+
"639_2_T": "ful",
|
| 683 |
+
"639_2_B": "ful",
|
| 684 |
+
"name": "Fulah"
|
| 685 |
+
},
|
| 686 |
+
{
|
| 687 |
+
"639_2_T": "fur",
|
| 688 |
+
"name": "Friulian"
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"639_2_T": "gaa",
|
| 692 |
+
"name": "Ga"
|
| 693 |
+
},
|
| 694 |
+
{
|
| 695 |
+
"639_2_T": "gay",
|
| 696 |
+
"name": "Gayo"
|
| 697 |
+
},
|
| 698 |
+
{
|
| 699 |
+
"639_2_T": "gba",
|
| 700 |
+
"name": "Gbaya"
|
| 701 |
+
},
|
| 702 |
+
{
|
| 703 |
+
"639_2_T": "gem",
|
| 704 |
+
"name": "Germanic languages"
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"639_2_T": "gez",
|
| 708 |
+
"name": "Geez"
|
| 709 |
+
},
|
| 710 |
+
{
|
| 711 |
+
"639_2_T": "gil",
|
| 712 |
+
"name": "Gilbertese"
|
| 713 |
+
},
|
| 714 |
+
{
|
| 715 |
+
"639_1": "gd",
|
| 716 |
+
"639_2_T": "gla",
|
| 717 |
+
"639_2_B": "gla",
|
| 718 |
+
"name": "Gaelic, Scottish Gaelic"
|
| 719 |
+
},
|
| 720 |
+
{
|
| 721 |
+
"639_1": "ga",
|
| 722 |
+
"639_2_T": "gle",
|
| 723 |
+
"639_2_B": "gle",
|
| 724 |
+
"name": "Irish"
|
| 725 |
+
},
|
| 726 |
+
{
|
| 727 |
+
"639_1": "gl",
|
| 728 |
+
"639_2_T": "glg",
|
| 729 |
+
"639_2_B": "glg",
|
| 730 |
+
"name": "Galician"
|
| 731 |
+
},
|
| 732 |
+
{
|
| 733 |
+
"639_1": "gv",
|
| 734 |
+
"639_2_T": "glv",
|
| 735 |
+
"639_2_B": "glv",
|
| 736 |
+
"name": "Manx"
|
| 737 |
+
},
|
| 738 |
+
{
|
| 739 |
+
"639_2_T": "gmh",
|
| 740 |
+
"name": "German, Middle High (ca.1050-1500)"
|
| 741 |
+
},
|
| 742 |
+
{
|
| 743 |
+
"639_2_T": "goh",
|
| 744 |
+
"name": "German, Old High (ca.750-1050)"
|
| 745 |
+
},
|
| 746 |
+
{
|
| 747 |
+
"639_2_T": "gon",
|
| 748 |
+
"name": "Gondi"
|
| 749 |
+
},
|
| 750 |
+
{
|
| 751 |
+
"639_2_T": "gor",
|
| 752 |
+
"name": "Gorontalo"
|
| 753 |
+
},
|
| 754 |
+
{
|
| 755 |
+
"639_2_T": "got",
|
| 756 |
+
"name": "Gothic"
|
| 757 |
+
},
|
| 758 |
+
{
|
| 759 |
+
"639_2_T": "grb",
|
| 760 |
+
"name": "Grebo"
|
| 761 |
+
},
|
| 762 |
+
{
|
| 763 |
+
"639_2_T": "grc",
|
| 764 |
+
"name": "Greek, Ancient (to 1453)"
|
| 765 |
+
},
|
| 766 |
+
{
|
| 767 |
+
"639_1": "gn",
|
| 768 |
+
"639_2_T": "grn",
|
| 769 |
+
"639_2_B": "grn",
|
| 770 |
+
"name": "Guarani"
|
| 771 |
+
},
|
| 772 |
+
{
|
| 773 |
+
"639_2_T": "gsw",
|
| 774 |
+
"name": "Swiss German; Alemannic; Alsatian"
|
| 775 |
+
},
|
| 776 |
+
{
|
| 777 |
+
"639_1": "gu",
|
| 778 |
+
"639_2_T": "guj",
|
| 779 |
+
"639_2_B": "guj",
|
| 780 |
+
"name": "Gujarati"
|
| 781 |
+
},
|
| 782 |
+
{
|
| 783 |
+
"639_2_T": "gwi",
|
| 784 |
+
"name": "Gwich'in"
|
| 785 |
+
},
|
| 786 |
+
{
|
| 787 |
+
"639_2_T": "hai",
|
| 788 |
+
"name": "Haida"
|
| 789 |
+
},
|
| 790 |
+
{
|
| 791 |
+
"639_1": "ht",
|
| 792 |
+
"639_2_T": "hat",
|
| 793 |
+
"639_2_B": "hat",
|
| 794 |
+
"name": "Haitian, Haitian Creole"
|
| 795 |
+
},
|
| 796 |
+
{
|
| 797 |
+
"639_1": "ha",
|
| 798 |
+
"639_2_T": "hau",
|
| 799 |
+
"639_2_B": "hau",
|
| 800 |
+
"name": "Hausa"
|
| 801 |
+
},
|
| 802 |
+
{
|
| 803 |
+
"639_2_T": "haw",
|
| 804 |
+
"name": "Hawaiian"
|
| 805 |
+
},
|
| 806 |
+
{
|
| 807 |
+
"639_1": "he",
|
| 808 |
+
"639_2_T": "heb",
|
| 809 |
+
"639_2_B": "heb",
|
| 810 |
+
"name": "Hebrew"
|
| 811 |
+
},
|
| 812 |
+
{
|
| 813 |
+
"639_1": "hz",
|
| 814 |
+
"639_2_T": "her",
|
| 815 |
+
"639_2_B": "her",
|
| 816 |
+
"name": "Herero"
|
| 817 |
+
},
|
| 818 |
+
{
|
| 819 |
+
"639_2_T": "hil",
|
| 820 |
+
"name": "Hiligaynon"
|
| 821 |
+
},
|
| 822 |
+
{
|
| 823 |
+
"639_2_T": "him",
|
| 824 |
+
"name": "Himachali languages; Western Pahari languages"
|
| 825 |
+
},
|
| 826 |
+
{
|
| 827 |
+
"639_1": "hi",
|
| 828 |
+
"639_2_T": "hin",
|
| 829 |
+
"639_2_B": "hin",
|
| 830 |
+
"name": "Hindi"
|
| 831 |
+
},
|
| 832 |
+
{
|
| 833 |
+
"639_2_T": "hit",
|
| 834 |
+
"name": "Hittite"
|
| 835 |
+
},
|
| 836 |
+
{
|
| 837 |
+
"639_2_T": "hmn",
|
| 838 |
+
"name": "Hmong; Mong"
|
| 839 |
+
},
|
| 840 |
+
{
|
| 841 |
+
"639_1": "ho",
|
| 842 |
+
"639_2_T": "hmo",
|
| 843 |
+
"639_2_B": "hmo",
|
| 844 |
+
"name": "Hiri Motu"
|
| 845 |
+
},
|
| 846 |
+
{
|
| 847 |
+
"639_1": "hr",
|
| 848 |
+
"639_2_T": "hrv",
|
| 849 |
+
"639_2_B": "hrv",
|
| 850 |
+
"name": "Croatian"
|
| 851 |
+
},
|
| 852 |
+
{
|
| 853 |
+
"639_2_T": "hsb",
|
| 854 |
+
"name": "Upper Sorbian"
|
| 855 |
+
},
|
| 856 |
+
{
|
| 857 |
+
"639_1": "hu",
|
| 858 |
+
"639_2_T": "hun",
|
| 859 |
+
"639_2_B": "hun",
|
| 860 |
+
"name": "Hungarian"
|
| 861 |
+
},
|
| 862 |
+
{
|
| 863 |
+
"639_2_T": "hup",
|
| 864 |
+
"name": "Hupa"
|
| 865 |
+
},
|
| 866 |
+
{
|
| 867 |
+
"639_1": "hy",
|
| 868 |
+
"639_2_T": "hye",
|
| 869 |
+
"639_2_B": "arm",
|
| 870 |
+
"name": "Armenian"
|
| 871 |
+
},
|
| 872 |
+
{
|
| 873 |
+
"639_2_T": "iba",
|
| 874 |
+
"name": "Iban"
|
| 875 |
+
},
|
| 876 |
+
{
|
| 877 |
+
"639_1": "ig",
|
| 878 |
+
"639_2_T": "ibo",
|
| 879 |
+
"639_2_B": "ibo",
|
| 880 |
+
"name": "Igbo"
|
| 881 |
+
},
|
| 882 |
+
{
|
| 883 |
+
"639_1": "io",
|
| 884 |
+
"639_2_T": "ido",
|
| 885 |
+
"639_2_B": "ido",
|
| 886 |
+
"name": "Ido"
|
| 887 |
+
},
|
| 888 |
+
{
|
| 889 |
+
"639_1": "ii",
|
| 890 |
+
"639_2_T": "iii",
|
| 891 |
+
"639_2_B": "iii",
|
| 892 |
+
"name": "Sichuan Yi, Nuosu"
|
| 893 |
+
},
|
| 894 |
+
{
|
| 895 |
+
"639_2_T": "ijo",
|
| 896 |
+
"name": "Ijo languages"
|
| 897 |
+
},
|
| 898 |
+
{
|
| 899 |
+
"639_1": "iu",
|
| 900 |
+
"639_2_T": "iku",
|
| 901 |
+
"639_2_B": "iku",
|
| 902 |
+
"name": "Inuktitut"
|
| 903 |
+
},
|
| 904 |
+
{
|
| 905 |
+
"639_1": "ie",
|
| 906 |
+
"639_2_T": "ile",
|
| 907 |
+
"639_2_B": "ile",
|
| 908 |
+
"name": "Interlingue, Occidental"
|
| 909 |
+
},
|
| 910 |
+
{
|
| 911 |
+
"639_2_T": "ilo",
|
| 912 |
+
"name": "Iloko"
|
| 913 |
+
},
|
| 914 |
+
{
|
| 915 |
+
"639_1": "ia",
|
| 916 |
+
"639_2_T": "ina",
|
| 917 |
+
"639_2_B": "ina",
|
| 918 |
+
"name": "Interlingua (International Auxiliary Language Association)"
|
| 919 |
+
},
|
| 920 |
+
{
|
| 921 |
+
"639_2_T": "inc",
|
| 922 |
+
"name": "Indic languages"
|
| 923 |
+
},
|
| 924 |
+
{
|
| 925 |
+
"639_1": "id",
|
| 926 |
+
"639_2_T": "ind",
|
| 927 |
+
"639_2_B": "ind",
|
| 928 |
+
"name": "Indonesian"
|
| 929 |
+
},
|
| 930 |
+
{
|
| 931 |
+
"639_2_T": "ine",
|
| 932 |
+
"name": "Indo-European languages"
|
| 933 |
+
},
|
| 934 |
+
{
|
| 935 |
+
"639_2_T": "inh",
|
| 936 |
+
"name": "Ingush"
|
| 937 |
+
},
|
| 938 |
+
{
|
| 939 |
+
"639_1": "ik",
|
| 940 |
+
"639_2_T": "ipk",
|
| 941 |
+
"639_2_B": "ipk",
|
| 942 |
+
"name": "Inupiaq"
|
| 943 |
+
},
|
| 944 |
+
{
|
| 945 |
+
"639_2_T": "ira",
|
| 946 |
+
"name": "Iranian languages"
|
| 947 |
+
},
|
| 948 |
+
{
|
| 949 |
+
"639_2_T": "iro",
|
| 950 |
+
"name": "Iroquoian languages"
|
| 951 |
+
},
|
| 952 |
+
{
|
| 953 |
+
"639_1": "is",
|
| 954 |
+
"639_2_T": "isl",
|
| 955 |
+
"639_2_B": "ice",
|
| 956 |
+
"name": "Icelandic"
|
| 957 |
+
},
|
| 958 |
+
{
|
| 959 |
+
"639_1": "it",
|
| 960 |
+
"639_2_T": "ita",
|
| 961 |
+
"639_2_B": "ita",
|
| 962 |
+
"name": "Italian"
|
| 963 |
+
},
|
| 964 |
+
{
|
| 965 |
+
"639_1": "jv",
|
| 966 |
+
"639_2_T": "jav",
|
| 967 |
+
"639_2_B": "jav",
|
| 968 |
+
"name": "Javanese"
|
| 969 |
+
},
|
| 970 |
+
{
|
| 971 |
+
"639_2_T": "jbo",
|
| 972 |
+
"name": "Lojban"
|
| 973 |
+
},
|
| 974 |
+
{
|
| 975 |
+
"639_1": "ja",
|
| 976 |
+
"639_2_T": "jpn",
|
| 977 |
+
"639_2_B": "jpn",
|
| 978 |
+
"name": "Japanese"
|
| 979 |
+
},
|
| 980 |
+
{
|
| 981 |
+
"639_2_T": "jpr",
|
| 982 |
+
"name": "Judeo-Persian"
|
| 983 |
+
},
|
| 984 |
+
{
|
| 985 |
+
"639_2_T": "jrb",
|
| 986 |
+
"name": "Judeo-Arabic"
|
| 987 |
+
},
|
| 988 |
+
{
|
| 989 |
+
"639_2_T": "kaa",
|
| 990 |
+
"name": "Kara-Kalpak"
|
| 991 |
+
},
|
| 992 |
+
{
|
| 993 |
+
"639_2_T": "kab",
|
| 994 |
+
"name": "Kabyle"
|
| 995 |
+
},
|
| 996 |
+
{
|
| 997 |
+
"639_2_T": "kac",
|
| 998 |
+
"name": "Kachin; Jingpho"
|
| 999 |
+
},
|
| 1000 |
+
{
|
| 1001 |
+
"639_1": "kl",
|
| 1002 |
+
"639_2_T": "kal",
|
| 1003 |
+
"639_2_B": "kal",
|
| 1004 |
+
"name": "Kalaallisut, Greenlandic"
|
| 1005 |
+
},
|
| 1006 |
+
{
|
| 1007 |
+
"639_2_T": "kam",
|
| 1008 |
+
"name": "Kamba"
|
| 1009 |
+
},
|
| 1010 |
+
{
|
| 1011 |
+
"639_1": "kn",
|
| 1012 |
+
"639_2_T": "kan",
|
| 1013 |
+
"639_2_B": "kan",
|
| 1014 |
+
"name": "Kannada"
|
| 1015 |
+
},
|
| 1016 |
+
{
|
| 1017 |
+
"639_2_T": "kar",
|
| 1018 |
+
"name": "Karen languages"
|
| 1019 |
+
},
|
| 1020 |
+
{
|
| 1021 |
+
"639_1": "ks",
|
| 1022 |
+
"639_2_T": "kas",
|
| 1023 |
+
"639_2_B": "kas",
|
| 1024 |
+
"name": "Kashmiri"
|
| 1025 |
+
},
|
| 1026 |
+
{
|
| 1027 |
+
"639_1": "ka",
|
| 1028 |
+
"639_2_T": "kat",
|
| 1029 |
+
"639_2_B": "geo",
|
| 1030 |
+
"name": "Georgian"
|
| 1031 |
+
},
|
| 1032 |
+
{
|
| 1033 |
+
"639_1": "kr",
|
| 1034 |
+
"639_2_T": "kau",
|
| 1035 |
+
"639_2_B": "kau",
|
| 1036 |
+
"name": "Kanuri"
|
| 1037 |
+
},
|
| 1038 |
+
{
|
| 1039 |
+
"639_2_T": "kaw",
|
| 1040 |
+
"name": "Kawi"
|
| 1041 |
+
},
|
| 1042 |
+
{
|
| 1043 |
+
"639_1": "kk",
|
| 1044 |
+
"639_2_T": "kaz",
|
| 1045 |
+
"639_2_B": "kaz",
|
| 1046 |
+
"name": "Kazakh"
|
| 1047 |
+
},
|
| 1048 |
+
{
|
| 1049 |
+
"639_2_T": "kbd",
|
| 1050 |
+
"name": "Kabardian"
|
| 1051 |
+
},
|
| 1052 |
+
{
|
| 1053 |
+
"639_2_T": "kha",
|
| 1054 |
+
"name": "Khasi"
|
| 1055 |
+
},
|
| 1056 |
+
{
|
| 1057 |
+
"639_2_T": "khi",
|
| 1058 |
+
"name": "Khoisan languages"
|
| 1059 |
+
},
|
| 1060 |
+
{
|
| 1061 |
+
"639_1": "km",
|
| 1062 |
+
"639_2_T": "khm",
|
| 1063 |
+
"639_2_B": "khm",
|
| 1064 |
+
"name": "Central Khmer"
|
| 1065 |
+
},
|
| 1066 |
+
{
|
| 1067 |
+
"639_2_T": "kho",
|
| 1068 |
+
"name": "Khotanese; Sakan"
|
| 1069 |
+
},
|
| 1070 |
+
{
|
| 1071 |
+
"639_1": "ki",
|
| 1072 |
+
"639_2_T": "kik",
|
| 1073 |
+
"639_2_B": "kik",
|
| 1074 |
+
"name": "Kikuyu, Gikuyu"
|
| 1075 |
+
},
|
| 1076 |
+
{
|
| 1077 |
+
"639_1": "rw",
|
| 1078 |
+
"639_2_T": "kin",
|
| 1079 |
+
"639_2_B": "kin",
|
| 1080 |
+
"name": "Kinyarwanda"
|
| 1081 |
+
},
|
| 1082 |
+
{
|
| 1083 |
+
"639_1": "ky",
|
| 1084 |
+
"639_2_T": "kir",
|
| 1085 |
+
"639_2_B": "kir",
|
| 1086 |
+
"name": "Kirghiz, Kyrgyz"
|
| 1087 |
+
},
|
| 1088 |
+
{
|
| 1089 |
+
"639_2_T": "kmb",
|
| 1090 |
+
"name": "Kimbundu"
|
| 1091 |
+
},
|
| 1092 |
+
{
|
| 1093 |
+
"639_2_T": "kok",
|
| 1094 |
+
"name": "Konkani"
|
| 1095 |
+
},
|
| 1096 |
+
{
|
| 1097 |
+
"639_1": "kv",
|
| 1098 |
+
"639_2_T": "kom",
|
| 1099 |
+
"639_2_B": "kom",
|
| 1100 |
+
"name": "Komi"
|
| 1101 |
+
},
|
| 1102 |
+
{
|
| 1103 |
+
"639_1": "kg",
|
| 1104 |
+
"639_2_T": "kon",
|
| 1105 |
+
"639_2_B": "kon",
|
| 1106 |
+
"name": "Kongo"
|
| 1107 |
+
},
|
| 1108 |
+
{
|
| 1109 |
+
"639_1": "ko",
|
| 1110 |
+
"639_2_T": "kor",
|
| 1111 |
+
"639_2_B": "kor",
|
| 1112 |
+
"name": "Korean"
|
| 1113 |
+
},
|
| 1114 |
+
{
|
| 1115 |
+
"639_2_T": "kos",
|
| 1116 |
+
"name": "Kosraean"
|
| 1117 |
+
},
|
| 1118 |
+
{
|
| 1119 |
+
"639_2_T": "kpe",
|
| 1120 |
+
"name": "Kpelle"
|
| 1121 |
+
},
|
| 1122 |
+
{
|
| 1123 |
+
"639_2_T": "krc",
|
| 1124 |
+
"name": "Karachay-Balkar"
|
| 1125 |
+
},
|
| 1126 |
+
{
|
| 1127 |
+
"639_2_T": "krl",
|
| 1128 |
+
"name": "Karelian"
|
| 1129 |
+
},
|
| 1130 |
+
{
|
| 1131 |
+
"639_2_T": "kro",
|
| 1132 |
+
"name": "Kru languages"
|
| 1133 |
+
},
|
| 1134 |
+
{
|
| 1135 |
+
"639_2_T": "kru",
|
| 1136 |
+
"name": "Kurukh"
|
| 1137 |
+
},
|
| 1138 |
+
{
|
| 1139 |
+
"639_1": "kj",
|
| 1140 |
+
"639_2_T": "kua",
|
| 1141 |
+
"639_2_B": "kua",
|
| 1142 |
+
"name": "Kuanyama, Kwanyama"
|
| 1143 |
+
},
|
| 1144 |
+
{
|
| 1145 |
+
"639_2_T": "kum",
|
| 1146 |
+
"name": "Kumyk"
|
| 1147 |
+
},
|
| 1148 |
+
{
|
| 1149 |
+
"639_1": "ku",
|
| 1150 |
+
"639_2_T": "kur",
|
| 1151 |
+
"639_2_B": "kur",
|
| 1152 |
+
"name": "Kurdish"
|
| 1153 |
+
},
|
| 1154 |
+
{
|
| 1155 |
+
"639_2_T": "kut",
|
| 1156 |
+
"name": "Kutenai"
|
| 1157 |
+
},
|
| 1158 |
+
{
|
| 1159 |
+
"639_2_T": "lad",
|
| 1160 |
+
"name": "Ladino"
|
| 1161 |
+
},
|
| 1162 |
+
{
|
| 1163 |
+
"639_2_T": "lah",
|
| 1164 |
+
"name": "Lahnda"
|
| 1165 |
+
},
|
| 1166 |
+
{
|
| 1167 |
+
"639_2_T": "lam",
|
| 1168 |
+
"name": "Lamba"
|
| 1169 |
+
},
|
| 1170 |
+
{
|
| 1171 |
+
"639_1": "lo",
|
| 1172 |
+
"639_2_T": "lao",
|
| 1173 |
+
"639_2_B": "lao",
|
| 1174 |
+
"name": "Lao"
|
| 1175 |
+
},
|
| 1176 |
+
{
|
| 1177 |
+
"639_1": "la",
|
| 1178 |
+
"639_2_T": "lat",
|
| 1179 |
+
"639_2_B": "lat",
|
| 1180 |
+
"name": "Latin"
|
| 1181 |
+
},
|
| 1182 |
+
{
|
| 1183 |
+
"639_1": "lv",
|
| 1184 |
+
"639_2_T": "lav",
|
| 1185 |
+
"639_2_B": "lav",
|
| 1186 |
+
"name": "Latvian"
|
| 1187 |
+
},
|
| 1188 |
+
{
|
| 1189 |
+
"639_2_T": "lez",
|
| 1190 |
+
"name": "Lezghian"
|
| 1191 |
+
},
|
| 1192 |
+
{
|
| 1193 |
+
"639_1": "li",
|
| 1194 |
+
"639_2_T": "lim",
|
| 1195 |
+
"639_2_B": "lim",
|
| 1196 |
+
"name": "Limburgan, Limburger, Limburgish"
|
| 1197 |
+
},
|
| 1198 |
+
{
|
| 1199 |
+
"639_1": "ln",
|
| 1200 |
+
"639_2_T": "lin",
|
| 1201 |
+
"639_2_B": "lin",
|
| 1202 |
+
"name": "Lingala"
|
| 1203 |
+
},
|
| 1204 |
+
{
|
| 1205 |
+
"639_1": "lt",
|
| 1206 |
+
"639_2_T": "lit",
|
| 1207 |
+
"639_2_B": "lit",
|
| 1208 |
+
"name": "Lithuanian"
|
| 1209 |
+
},
|
| 1210 |
+
{
|
| 1211 |
+
"639_2_T": "lol",
|
| 1212 |
+
"name": "Mongo"
|
| 1213 |
+
},
|
| 1214 |
+
{
|
| 1215 |
+
"639_2_T": "loz",
|
| 1216 |
+
"name": "Lozi"
|
| 1217 |
+
},
|
| 1218 |
+
{
|
| 1219 |
+
"639_1": "lb",
|
| 1220 |
+
"639_2_T": "ltz",
|
| 1221 |
+
"639_2_B": "ltz",
|
| 1222 |
+
"name": "Luxembourgish, Letzeburgesch"
|
| 1223 |
+
},
|
| 1224 |
+
{
|
| 1225 |
+
"639_2_T": "lua",
|
| 1226 |
+
"name": "Luba-Lulua"
|
| 1227 |
+
},
|
| 1228 |
+
{
|
| 1229 |
+
"639_1": "lu",
|
| 1230 |
+
"639_2_T": "lub",
|
| 1231 |
+
"639_2_B": "lub",
|
| 1232 |
+
"name": "Luba-Katanga"
|
| 1233 |
+
},
|
| 1234 |
+
{
|
| 1235 |
+
"639_1": "lg",
|
| 1236 |
+
"639_2_T": "lug",
|
| 1237 |
+
"639_2_B": "lug",
|
| 1238 |
+
"name": "Ganda"
|
| 1239 |
+
},
|
| 1240 |
+
{
|
| 1241 |
+
"639_2_T": "lui",
|
| 1242 |
+
"name": "Luiseno"
|
| 1243 |
+
},
|
| 1244 |
+
{
|
| 1245 |
+
"639_2_T": "lun",
|
| 1246 |
+
"name": "Lunda"
|
| 1247 |
+
},
|
| 1248 |
+
{
|
| 1249 |
+
"639_2_T": "luo",
|
| 1250 |
+
"name": "Luo (Kenya and Tanzania)"
|
| 1251 |
+
},
|
| 1252 |
+
{
|
| 1253 |
+
"639_2_T": "lus",
|
| 1254 |
+
"name": "Lushai"
|
| 1255 |
+
},
|
| 1256 |
+
{
|
| 1257 |
+
"639_2_T": "mad",
|
| 1258 |
+
"name": "Madurese"
|
| 1259 |
+
},
|
| 1260 |
+
{
|
| 1261 |
+
"639_2_T": "mag",
|
| 1262 |
+
"name": "Magahi"
|
| 1263 |
+
},
|
| 1264 |
+
{
|
| 1265 |
+
"639_1": "mh",
|
| 1266 |
+
"639_2_T": "mah",
|
| 1267 |
+
"639_2_B": "mah",
|
| 1268 |
+
"name": "Marshallese"
|
| 1269 |
+
},
|
| 1270 |
+
{
|
| 1271 |
+
"639_2_T": "mai",
|
| 1272 |
+
"name": "Maithili"
|
| 1273 |
+
},
|
| 1274 |
+
{
|
| 1275 |
+
"639_2_T": "mak",
|
| 1276 |
+
"name": "Makasar"
|
| 1277 |
+
},
|
| 1278 |
+
{
|
| 1279 |
+
"639_1": "ml",
|
| 1280 |
+
"639_2_T": "mal",
|
| 1281 |
+
"639_2_B": "mal",
|
| 1282 |
+
"name": "Malayalam"
|
| 1283 |
+
},
|
| 1284 |
+
{
|
| 1285 |
+
"639_2_T": "man",
|
| 1286 |
+
"name": "Mandingo"
|
| 1287 |
+
},
|
| 1288 |
+
{
|
| 1289 |
+
"639_2_T": "map",
|
| 1290 |
+
"name": "Austronesian languages"
|
| 1291 |
+
},
|
| 1292 |
+
{
|
| 1293 |
+
"639_1": "mr",
|
| 1294 |
+
"639_2_T": "mar",
|
| 1295 |
+
"639_2_B": "mar",
|
| 1296 |
+
"name": "Marathi"
|
| 1297 |
+
},
|
| 1298 |
+
{
|
| 1299 |
+
"639_2_T": "mas",
|
| 1300 |
+
"name": "Masai"
|
| 1301 |
+
},
|
| 1302 |
+
{
|
| 1303 |
+
"639_2_T": "mdf",
|
| 1304 |
+
"name": "Moksha"
|
| 1305 |
+
},
|
| 1306 |
+
{
|
| 1307 |
+
"639_2_T": "mdr",
|
| 1308 |
+
"name": "Mandar"
|
| 1309 |
+
},
|
| 1310 |
+
{
|
| 1311 |
+
"639_2_T": "men",
|
| 1312 |
+
"name": "Mende"
|
| 1313 |
+
},
|
| 1314 |
+
{
|
| 1315 |
+
"639_2_T": "mga",
|
| 1316 |
+
"name": "Irish, Middle (900-1200)"
|
| 1317 |
+
},
|
| 1318 |
+
{
|
| 1319 |
+
"639_2_T": "mic",
|
| 1320 |
+
"name": "Mi'kmaq; Micmac"
|
| 1321 |
+
},
|
| 1322 |
+
{
|
| 1323 |
+
"639_2_T": "min",
|
| 1324 |
+
"name": "Minangkabau"
|
| 1325 |
+
},
|
| 1326 |
+
{
|
| 1327 |
+
"639_2_T": "mis",
|
| 1328 |
+
"name": "Uncoded languages"
|
| 1329 |
+
},
|
| 1330 |
+
{
|
| 1331 |
+
"639_1": "mk",
|
| 1332 |
+
"639_2_T": "mkd",
|
| 1333 |
+
"639_2_B": "mac",
|
| 1334 |
+
"name": "Macedonian"
|
| 1335 |
+
},
|
| 1336 |
+
{
|
| 1337 |
+
"639_2_T": "mkh",
|
| 1338 |
+
"name": "Mon-Khmer languages"
|
| 1339 |
+
},
|
| 1340 |
+
{
|
| 1341 |
+
"639_1": "mg",
|
| 1342 |
+
"639_2_T": "mlg",
|
| 1343 |
+
"639_2_B": "mlg",
|
| 1344 |
+
"name": "Malagasy"
|
| 1345 |
+
},
|
| 1346 |
+
{
|
| 1347 |
+
"639_1": "mt",
|
| 1348 |
+
"639_2_T": "mlt",
|
| 1349 |
+
"639_2_B": "mlt",
|
| 1350 |
+
"name": "Maltese"
|
| 1351 |
+
},
|
| 1352 |
+
{
|
| 1353 |
+
"639_2_T": "mnc",
|
| 1354 |
+
"name": "Manchu"
|
| 1355 |
+
},
|
| 1356 |
+
{
|
| 1357 |
+
"639_2_T": "mni",
|
| 1358 |
+
"name": "Manipuri"
|
| 1359 |
+
},
|
| 1360 |
+
{
|
| 1361 |
+
"639_2_T": "mno",
|
| 1362 |
+
"name": "Manobo languages"
|
| 1363 |
+
},
|
| 1364 |
+
{
|
| 1365 |
+
"639_2_T": "moh",
|
| 1366 |
+
"name": "Mohawk"
|
| 1367 |
+
},
|
| 1368 |
+
{
|
| 1369 |
+
"639_1": "mn",
|
| 1370 |
+
"639_2_T": "mon",
|
| 1371 |
+
"639_2_B": "mon",
|
| 1372 |
+
"name": "Mongolian"
|
| 1373 |
+
},
|
| 1374 |
+
{
|
| 1375 |
+
"639_2_T": "mos",
|
| 1376 |
+
"name": "Mossi"
|
| 1377 |
+
},
|
| 1378 |
+
{
|
| 1379 |
+
"639_1": "mi",
|
| 1380 |
+
"639_2_T": "mri",
|
| 1381 |
+
"639_2_B": "mao",
|
| 1382 |
+
"name": "Maori"
|
| 1383 |
+
},
|
| 1384 |
+
{
|
| 1385 |
+
"639_1": "ms",
|
| 1386 |
+
"639_2_T": "msa",
|
| 1387 |
+
"639_2_B": "may",
|
| 1388 |
+
"name": "Malay"
|
| 1389 |
+
},
|
| 1390 |
+
{
|
| 1391 |
+
"639_2_T": "mul",
|
| 1392 |
+
"name": "Multiple languages"
|
| 1393 |
+
},
|
| 1394 |
+
{
|
| 1395 |
+
"639_2_T": "mun",
|
| 1396 |
+
"name": "Munda languages"
|
| 1397 |
+
},
|
| 1398 |
+
{
|
| 1399 |
+
"639_2_T": "mus",
|
| 1400 |
+
"name": "Creek"
|
| 1401 |
+
},
|
| 1402 |
+
{
|
| 1403 |
+
"639_2_T": "mwl",
|
| 1404 |
+
"name": "Mirandese"
|
| 1405 |
+
},
|
| 1406 |
+
{
|
| 1407 |
+
"639_2_T": "mwr",
|
| 1408 |
+
"name": "Marwari"
|
| 1409 |
+
},
|
| 1410 |
+
{
|
| 1411 |
+
"639_1": "my",
|
| 1412 |
+
"639_2_T": "mya",
|
| 1413 |
+
"639_2_B": "bur",
|
| 1414 |
+
"name": "Burmese"
|
| 1415 |
+
},
|
| 1416 |
+
{
|
| 1417 |
+
"639_2_T": "myn",
|
| 1418 |
+
"name": "Mayan languages"
|
| 1419 |
+
},
|
| 1420 |
+
{
|
| 1421 |
+
"639_2_T": "myv",
|
| 1422 |
+
"name": "Erzya"
|
| 1423 |
+
},
|
| 1424 |
+
{
|
| 1425 |
+
"639_2_T": "nah",
|
| 1426 |
+
"name": "Nahuatl languages"
|
| 1427 |
+
},
|
| 1428 |
+
{
|
| 1429 |
+
"639_2_T": "nai",
|
| 1430 |
+
"name": "North American Indian languages"
|
| 1431 |
+
},
|
| 1432 |
+
{
|
| 1433 |
+
"639_2_T": "nap",
|
| 1434 |
+
"name": "Neapolitan"
|
| 1435 |
+
},
|
| 1436 |
+
{
|
| 1437 |
+
"639_1": "na",
|
| 1438 |
+
"639_2_T": "nau",
|
| 1439 |
+
"639_2_B": "nau",
|
| 1440 |
+
"name": "Nauru"
|
| 1441 |
+
},
|
| 1442 |
+
{
|
| 1443 |
+
"639_1": "nv",
|
| 1444 |
+
"639_2_T": "nav",
|
| 1445 |
+
"639_2_B": "nav",
|
| 1446 |
+
"name": "Navajo, Navaho"
|
| 1447 |
+
},
|
| 1448 |
+
{
|
| 1449 |
+
"639_1": "nr",
|
| 1450 |
+
"639_2_T": "nbl",
|
| 1451 |
+
"639_2_B": "nbl",
|
| 1452 |
+
"name": "South Ndebele"
|
| 1453 |
+
},
|
| 1454 |
+
{
|
| 1455 |
+
"639_1": "nd",
|
| 1456 |
+
"639_2_T": "nde",
|
| 1457 |
+
"639_2_B": "nde",
|
| 1458 |
+
"name": "North Ndebele"
|
| 1459 |
+
},
|
| 1460 |
+
{
|
| 1461 |
+
"639_1": "ng",
|
| 1462 |
+
"639_2_T": "ndo",
|
| 1463 |
+
"639_2_B": "ndo",
|
| 1464 |
+
"name": "Ndonga"
|
| 1465 |
+
},
|
| 1466 |
+
{
|
| 1467 |
+
"639_2_T": "nds",
|
| 1468 |
+
"name": "Low German; Low Saxon; German, Low; Saxon, Low"
|
| 1469 |
+
},
|
| 1470 |
+
{
|
| 1471 |
+
"639_1": "ne",
|
| 1472 |
+
"639_2_T": "nep",
|
| 1473 |
+
"639_2_B": "nep",
|
| 1474 |
+
"name": "Nepali"
|
| 1475 |
+
},
|
| 1476 |
+
{
|
| 1477 |
+
"639_2_T": "new",
|
| 1478 |
+
"name": "Nepal Bhasa; Newari"
|
| 1479 |
+
},
|
| 1480 |
+
{
|
| 1481 |
+
"639_2_T": "nia",
|
| 1482 |
+
"name": "Nias"
|
| 1483 |
+
},
|
| 1484 |
+
{
|
| 1485 |
+
"639_2_T": "nic",
|
| 1486 |
+
"name": "Niger-Kordofanian languages"
|
| 1487 |
+
},
|
| 1488 |
+
{
|
| 1489 |
+
"639_2_T": "niu",
|
| 1490 |
+
"name": "Niuean"
|
| 1491 |
+
},
|
| 1492 |
+
{
|
| 1493 |
+
"639_1": "nl",
|
| 1494 |
+
"639_2_T": "nld",
|
| 1495 |
+
"639_2_B": "dut",
|
| 1496 |
+
"name": "Dutch, Flemish"
|
| 1497 |
+
},
|
| 1498 |
+
{
|
| 1499 |
+
"639_1": "nl",
|
| 1500 |
+
"639_2_T": "nld",
|
| 1501 |
+
"639_2_B": "dut",
|
| 1502 |
+
"name": "Dutch; Flemish"
|
| 1503 |
+
},
|
| 1504 |
+
{
|
| 1505 |
+
"639_1": "nn",
|
| 1506 |
+
"639_2_T": "nno",
|
| 1507 |
+
"639_2_B": "nno",
|
| 1508 |
+
"name": "Norwegian Nynorsk"
|
| 1509 |
+
},
|
| 1510 |
+
{
|
| 1511 |
+
"639_1": "nb",
|
| 1512 |
+
"639_2_T": "nob",
|
| 1513 |
+
"639_2_B": "nob",
|
| 1514 |
+
"name": "Norwegian Bokmål"
|
| 1515 |
+
},
|
| 1516 |
+
{
|
| 1517 |
+
"639_2_T": "nog",
|
| 1518 |
+
"name": "Nogai"
|
| 1519 |
+
},
|
| 1520 |
+
{
|
| 1521 |
+
"639_2_T": "non",
|
| 1522 |
+
"name": "Norse, Old"
|
| 1523 |
+
},
|
| 1524 |
+
{
|
| 1525 |
+
"639_1": "no",
|
| 1526 |
+
"639_2_T": "nor",
|
| 1527 |
+
"639_2_B": "nor",
|
| 1528 |
+
"name": "Norwegian"
|
| 1529 |
+
},
|
| 1530 |
+
{
|
| 1531 |
+
"639_2_T": "nqo",
|
| 1532 |
+
"name": "N'Ko"
|
| 1533 |
+
},
|
| 1534 |
+
{
|
| 1535 |
+
"639_2_T": "nso",
|
| 1536 |
+
"name": "Pedi; Sepedi; Northern Sotho"
|
| 1537 |
+
},
|
| 1538 |
+
{
|
| 1539 |
+
"639_2_T": "nub",
|
| 1540 |
+
"name": "Nubian languages"
|
| 1541 |
+
},
|
| 1542 |
+
{
|
| 1543 |
+
"639_2_T": "nwc",
|
| 1544 |
+
"name": "Classical Newari; Old Newari; Classical Nepal Bhasa"
|
| 1545 |
+
},
|
| 1546 |
+
{
|
| 1547 |
+
"639_1": "ny",
|
| 1548 |
+
"639_2_T": "nya",
|
| 1549 |
+
"639_2_B": "nya",
|
| 1550 |
+
"name": "Chichewa, Chewa, Nyanja"
|
| 1551 |
+
},
|
| 1552 |
+
{
|
| 1553 |
+
"639_2_T": "nym",
|
| 1554 |
+
"name": "Nyamwezi"
|
| 1555 |
+
},
|
| 1556 |
+
{
|
| 1557 |
+
"639_2_T": "nyn",
|
| 1558 |
+
"name": "Nyankole"
|
| 1559 |
+
},
|
| 1560 |
+
{
|
| 1561 |
+
"639_2_T": "nyo",
|
| 1562 |
+
"name": "Nyoro"
|
| 1563 |
+
},
|
| 1564 |
+
{
|
| 1565 |
+
"639_2_T": "nzi",
|
| 1566 |
+
"name": "Nzima"
|
| 1567 |
+
},
|
| 1568 |
+
{
|
| 1569 |
+
"639_1": "oc",
|
| 1570 |
+
"639_2_T": "oci",
|
| 1571 |
+
"639_2_B": "oci",
|
| 1572 |
+
"name": "Occitan"
|
| 1573 |
+
},
|
| 1574 |
+
{
|
| 1575 |
+
"639_1": "oj",
|
| 1576 |
+
"639_2_T": "oji",
|
| 1577 |
+
"639_2_B": "oji",
|
| 1578 |
+
"name": "Ojibwa"
|
| 1579 |
+
},
|
| 1580 |
+
{
|
| 1581 |
+
"639_1": "or",
|
| 1582 |
+
"639_2_T": "ori",
|
| 1583 |
+
"639_2_B": "ori",
|
| 1584 |
+
"name": "Oriya"
|
| 1585 |
+
},
|
| 1586 |
+
{
|
| 1587 |
+
"639_1": "om",
|
| 1588 |
+
"639_2_T": "orm",
|
| 1589 |
+
"639_2_B": "orm",
|
| 1590 |
+
"name": "Oromo"
|
| 1591 |
+
},
|
| 1592 |
+
{
|
| 1593 |
+
"639_2_T": "osa",
|
| 1594 |
+
"name": "Osage"
|
| 1595 |
+
},
|
| 1596 |
+
{
|
| 1597 |
+
"639_1": "os",
|
| 1598 |
+
"639_2_T": "oss",
|
| 1599 |
+
"639_2_B": "oss",
|
| 1600 |
+
"name": "Ossetian, Ossetic"
|
| 1601 |
+
},
|
| 1602 |
+
{
|
| 1603 |
+
"639_2_T": "ota",
|
| 1604 |
+
"name": "Turkish, Ottoman (1500-1928)"
|
| 1605 |
+
},
|
| 1606 |
+
{
|
| 1607 |
+
"639_2_T": "oto",
|
| 1608 |
+
"name": "Otomian languages"
|
| 1609 |
+
},
|
| 1610 |
+
{
|
| 1611 |
+
"639_2_T": "paa",
|
| 1612 |
+
"name": "Papuan languages"
|
| 1613 |
+
},
|
| 1614 |
+
{
|
| 1615 |
+
"639_2_T": "pag",
|
| 1616 |
+
"name": "Pangasinan"
|
| 1617 |
+
},
|
| 1618 |
+
{
|
| 1619 |
+
"639_2_T": "pal",
|
| 1620 |
+
"name": "Pahlavi"
|
| 1621 |
+
},
|
| 1622 |
+
{
|
| 1623 |
+
"639_2_T": "pam",
|
| 1624 |
+
"name": "Pampanga; Kapampangan"
|
| 1625 |
+
},
|
| 1626 |
+
{
|
| 1627 |
+
"639_1": "pa",
|
| 1628 |
+
"639_2_T": "pan",
|
| 1629 |
+
"639_2_B": "pan",
|
| 1630 |
+
"name": "Punjabi, Panjabi"
|
| 1631 |
+
},
|
| 1632 |
+
{
|
| 1633 |
+
"639_2_T": "pap",
|
| 1634 |
+
"name": "Papiamento"
|
| 1635 |
+
},
|
| 1636 |
+
{
|
| 1637 |
+
"639_2_T": "pau",
|
| 1638 |
+
"name": "Palauan"
|
| 1639 |
+
},
|
| 1640 |
+
{
|
| 1641 |
+
"639_2_T": "peo",
|
| 1642 |
+
"name": "Persian, Old (ca.600-400 B.C.)"
|
| 1643 |
+
},
|
| 1644 |
+
{
|
| 1645 |
+
"639_2_T": "phi",
|
| 1646 |
+
"name": "Philippine languages"
|
| 1647 |
+
},
|
| 1648 |
+
{
|
| 1649 |
+
"639_2_T": "phn",
|
| 1650 |
+
"name": "Phoenician"
|
| 1651 |
+
},
|
| 1652 |
+
{
|
| 1653 |
+
"639_1": "pi",
|
| 1654 |
+
"639_2_T": "pli",
|
| 1655 |
+
"639_2_B": "pli",
|
| 1656 |
+
"name": "Pali"
|
| 1657 |
+
},
|
| 1658 |
+
{
|
| 1659 |
+
"639_1": "pl",
|
| 1660 |
+
"639_2_T": "pol",
|
| 1661 |
+
"639_2_B": "pol",
|
| 1662 |
+
"name": "Polish"
|
| 1663 |
+
},
|
| 1664 |
+
{
|
| 1665 |
+
"639_2_T": "pon",
|
| 1666 |
+
"name": "Pohnpeian"
|
| 1667 |
+
},
|
| 1668 |
+
{
|
| 1669 |
+
"639_1": "pt",
|
| 1670 |
+
"639_2_T": "por",
|
| 1671 |
+
"639_2_B": "por",
|
| 1672 |
+
"name": "Portuguese"
|
| 1673 |
+
},
|
| 1674 |
+
{
|
| 1675 |
+
"639_2_T": "pra",
|
| 1676 |
+
"name": "Prakrit languages"
|
| 1677 |
+
},
|
| 1678 |
+
{
|
| 1679 |
+
"639_2_T": "pro",
|
| 1680 |
+
"name": "Provençal, Old (to 1500);Occitan, Old (to 1500)"
|
| 1681 |
+
},
|
| 1682 |
+
{
|
| 1683 |
+
"639_1": "ps",
|
| 1684 |
+
"639_2_T": "pus",
|
| 1685 |
+
"639_2_B": "pus",
|
| 1686 |
+
"name": "Pashto, Pushto"
|
| 1687 |
+
},
|
| 1688 |
+
{
|
| 1689 |
+
"639_2_T": "qaa-qtz",
|
| 1690 |
+
"name": "Reserved for local use"
|
| 1691 |
+
},
|
| 1692 |
+
{
|
| 1693 |
+
"639_1": "qu",
|
| 1694 |
+
"639_2_T": "que",
|
| 1695 |
+
"639_2_B": "que",
|
| 1696 |
+
"name": "Quechua"
|
| 1697 |
+
},
|
| 1698 |
+
{
|
| 1699 |
+
"639_2_T": "raj",
|
| 1700 |
+
"name": "Rajasthani"
|
| 1701 |
+
},
|
| 1702 |
+
{
|
| 1703 |
+
"639_2_T": "rap",
|
| 1704 |
+
"name": "Rapanui"
|
| 1705 |
+
},
|
| 1706 |
+
{
|
| 1707 |
+
"639_2_T": "rar",
|
| 1708 |
+
"name": "Rarotongan; Cook Islands Maori"
|
| 1709 |
+
},
|
| 1710 |
+
{
|
| 1711 |
+
"639_2_T": "roa",
|
| 1712 |
+
"name": "Romance languages"
|
| 1713 |
+
},
|
| 1714 |
+
{
|
| 1715 |
+
"639_1": "rm",
|
| 1716 |
+
"639_2_T": "roh",
|
| 1717 |
+
"639_2_B": "roh",
|
| 1718 |
+
"name": "Romansh"
|
| 1719 |
+
},
|
| 1720 |
+
{
|
| 1721 |
+
"639_2_T": "rom",
|
| 1722 |
+
"name": "Romany"
|
| 1723 |
+
},
|
| 1724 |
+
{
|
| 1725 |
+
"639_1": "ro",
|
| 1726 |
+
"639_2_T": "ron",
|
| 1727 |
+
"639_2_B": "rum",
|
| 1728 |
+
"name": "Romanian, Moldavian, Moldovan"
|
| 1729 |
+
},
|
| 1730 |
+
{
|
| 1731 |
+
"639_1": "ro",
|
| 1732 |
+
"639_2_T": "ron",
|
| 1733 |
+
"639_2_B": "rum",
|
| 1734 |
+
"name": "Romanian; Moldavian; Moldovan"
|
| 1735 |
+
},
|
| 1736 |
+
{
|
| 1737 |
+
"639_1": "rn",
|
| 1738 |
+
"639_2_T": "run",
|
| 1739 |
+
"639_2_B": "run",
|
| 1740 |
+
"name": "Rundi"
|
| 1741 |
+
},
|
| 1742 |
+
{
|
| 1743 |
+
"639_2_T": "rup",
|
| 1744 |
+
"name": "Aromanian; Arumanian; Macedo-Romanian"
|
| 1745 |
+
},
|
| 1746 |
+
{
|
| 1747 |
+
"639_1": "ru",
|
| 1748 |
+
"639_2_T": "rus",
|
| 1749 |
+
"639_2_B": "rus",
|
| 1750 |
+
"name": "Russian"
|
| 1751 |
+
},
|
| 1752 |
+
{
|
| 1753 |
+
"639_2_T": "sad",
|
| 1754 |
+
"name": "Sandawe"
|
| 1755 |
+
},
|
| 1756 |
+
{
|
| 1757 |
+
"639_1": "sg",
|
| 1758 |
+
"639_2_T": "sag",
|
| 1759 |
+
"639_2_B": "sag",
|
| 1760 |
+
"name": "Sango"
|
| 1761 |
+
},
|
| 1762 |
+
{
|
| 1763 |
+
"639_2_T": "sah",
|
| 1764 |
+
"name": "Yakut"
|
| 1765 |
+
},
|
| 1766 |
+
{
|
| 1767 |
+
"639_2_T": "sai",
|
| 1768 |
+
"name": "South American Indian languages"
|
| 1769 |
+
},
|
| 1770 |
+
{
|
| 1771 |
+
"639_2_T": "sal",
|
| 1772 |
+
"name": "Salishan languages"
|
| 1773 |
+
},
|
| 1774 |
+
{
|
| 1775 |
+
"639_2_T": "sam",
|
| 1776 |
+
"name": "Samaritan Aramaic"
|
| 1777 |
+
},
|
| 1778 |
+
{
|
| 1779 |
+
"639_1": "sa",
|
| 1780 |
+
"639_2_T": "san",
|
| 1781 |
+
"639_2_B": "san",
|
| 1782 |
+
"name": "Sanskrit"
|
| 1783 |
+
},
|
| 1784 |
+
{
|
| 1785 |
+
"639_2_T": "sas",
|
| 1786 |
+
"name": "Sasak"
|
| 1787 |
+
},
|
| 1788 |
+
{
|
| 1789 |
+
"639_2_T": "sat",
|
| 1790 |
+
"name": "Santali"
|
| 1791 |
+
},
|
| 1792 |
+
{
|
| 1793 |
+
"639_2_T": "scn",
|
| 1794 |
+
"name": "Sicilian"
|
| 1795 |
+
},
|
| 1796 |
+
{
|
| 1797 |
+
"639_2_T": "sco",
|
| 1798 |
+
"name": "Scots"
|
| 1799 |
+
},
|
| 1800 |
+
{
|
| 1801 |
+
"639_2_T": "sel",
|
| 1802 |
+
"name": "Selkup"
|
| 1803 |
+
},
|
| 1804 |
+
{
|
| 1805 |
+
"639_2_T": "sem",
|
| 1806 |
+
"name": "Semitic languages"
|
| 1807 |
+
},
|
| 1808 |
+
{
|
| 1809 |
+
"639_2_T": "sga",
|
| 1810 |
+
"name": "Irish, Old (to 900)"
|
| 1811 |
+
},
|
| 1812 |
+
{
|
| 1813 |
+
"639_2_T": "sgn",
|
| 1814 |
+
"name": "Sign Languages"
|
| 1815 |
+
},
|
| 1816 |
+
{
|
| 1817 |
+
"639_2_T": "shn",
|
| 1818 |
+
"name": "Shan"
|
| 1819 |
+
},
|
| 1820 |
+
{
|
| 1821 |
+
"639_2_T": "sid",
|
| 1822 |
+
"name": "Sidamo"
|
| 1823 |
+
},
|
| 1824 |
+
{
|
| 1825 |
+
"639_1": "si",
|
| 1826 |
+
"639_2_T": "sin",
|
| 1827 |
+
"639_2_B": "sin",
|
| 1828 |
+
"name": "Sinhala, Sinhalese"
|
| 1829 |
+
},
|
| 1830 |
+
{
|
| 1831 |
+
"639_2_T": "sio",
|
| 1832 |
+
"name": "Siouan languages"
|
| 1833 |
+
},
|
| 1834 |
+
{
|
| 1835 |
+
"639_2_T": "sit",
|
| 1836 |
+
"name": "Sino-Tibetan languages"
|
| 1837 |
+
},
|
| 1838 |
+
{
|
| 1839 |
+
"639_2_T": "sla",
|
| 1840 |
+
"name": "Slavic languages"
|
| 1841 |
+
},
|
| 1842 |
+
{
|
| 1843 |
+
"639_1": "sk",
|
| 1844 |
+
"639_2_T": "slk",
|
| 1845 |
+
"639_2_B": "slo",
|
| 1846 |
+
"name": "Slovak"
|
| 1847 |
+
},
|
| 1848 |
+
{
|
| 1849 |
+
"639_1": "sl",
|
| 1850 |
+
"639_2_T": "slv",
|
| 1851 |
+
"639_2_B": "slv",
|
| 1852 |
+
"name": "Slovenian"
|
| 1853 |
+
},
|
| 1854 |
+
{
|
| 1855 |
+
"639_2_T": "sma",
|
| 1856 |
+
"name": "Southern Sami"
|
| 1857 |
+
},
|
| 1858 |
+
{
|
| 1859 |
+
"639_1": "se",
|
| 1860 |
+
"639_2_T": "sme",
|
| 1861 |
+
"639_2_B": "sme",
|
| 1862 |
+
"name": "Northern Sami"
|
| 1863 |
+
},
|
| 1864 |
+
{
|
| 1865 |
+
"639_2_T": "smi",
|
| 1866 |
+
"name": "Sami languages"
|
| 1867 |
+
},
|
| 1868 |
+
{
|
| 1869 |
+
"639_2_T": "smj",
|
| 1870 |
+
"name": "Lule Sami"
|
| 1871 |
+
},
|
| 1872 |
+
{
|
| 1873 |
+
"639_2_T": "smn",
|
| 1874 |
+
"name": "Inari Sami"
|
| 1875 |
+
},
|
| 1876 |
+
{
|
| 1877 |
+
"639_1": "sm",
|
| 1878 |
+
"639_2_T": "smo",
|
| 1879 |
+
"639_2_B": "smo",
|
| 1880 |
+
"name": "Samoan"
|
| 1881 |
+
},
|
| 1882 |
+
{
|
| 1883 |
+
"639_2_T": "sms",
|
| 1884 |
+
"name": "Skolt Sami"
|
| 1885 |
+
},
|
| 1886 |
+
{
|
| 1887 |
+
"639_1": "sn",
|
| 1888 |
+
"639_2_T": "sna",
|
| 1889 |
+
"639_2_B": "sna",
|
| 1890 |
+
"name": "Shona"
|
| 1891 |
+
},
|
| 1892 |
+
{
|
| 1893 |
+
"639_1": "sd",
|
| 1894 |
+
"639_2_T": "snd",
|
| 1895 |
+
"639_2_B": "snd",
|
| 1896 |
+
"name": "Sindhi"
|
| 1897 |
+
},
|
| 1898 |
+
{
|
| 1899 |
+
"639_2_T": "snk",
|
| 1900 |
+
"name": "Soninke"
|
| 1901 |
+
},
|
| 1902 |
+
{
|
| 1903 |
+
"639_2_T": "sog",
|
| 1904 |
+
"name": "Sogdian"
|
| 1905 |
+
},
|
| 1906 |
+
{
|
| 1907 |
+
"639_1": "so",
|
| 1908 |
+
"639_2_T": "som",
|
| 1909 |
+
"639_2_B": "som",
|
| 1910 |
+
"name": "Somali"
|
| 1911 |
+
},
|
| 1912 |
+
{
|
| 1913 |
+
"639_2_T": "son",
|
| 1914 |
+
"name": "Songhai languages"
|
| 1915 |
+
},
|
| 1916 |
+
{
|
| 1917 |
+
"639_1": "st",
|
| 1918 |
+
"639_2_T": "sot",
|
| 1919 |
+
"639_2_B": "sot",
|
| 1920 |
+
"name": "Southern Sotho"
|
| 1921 |
+
},
|
| 1922 |
+
{
|
| 1923 |
+
"639_1": "es",
|
| 1924 |
+
"639_2_T": "spa",
|
| 1925 |
+
"639_2_B": "spa",
|
| 1926 |
+
"name": "Spanish, Castilian"
|
| 1927 |
+
},
|
| 1928 |
+
{
|
| 1929 |
+
"639_1": "sq",
|
| 1930 |
+
"639_2_T": "sqi",
|
| 1931 |
+
"639_2_B": "alb",
|
| 1932 |
+
"name": "Albanian"
|
| 1933 |
+
},
|
| 1934 |
+
{
|
| 1935 |
+
"639_1": "sc",
|
| 1936 |
+
"639_2_T": "srd",
|
| 1937 |
+
"639_2_B": "srd",
|
| 1938 |
+
"name": "Sardinian"
|
| 1939 |
+
},
|
| 1940 |
+
{
|
| 1941 |
+
"639_2_T": "srn",
|
| 1942 |
+
"name": "Sranan Tongo"
|
| 1943 |
+
},
|
| 1944 |
+
{
|
| 1945 |
+
"639_1": "sr",
|
| 1946 |
+
"639_2_T": "srp",
|
| 1947 |
+
"639_2_B": "srp",
|
| 1948 |
+
"name": "Serbian"
|
| 1949 |
+
},
|
| 1950 |
+
{
|
| 1951 |
+
"639_2_T": "srr",
|
| 1952 |
+
"name": "Serer"
|
| 1953 |
+
},
|
| 1954 |
+
{
|
| 1955 |
+
"639_2_T": "ssa",
|
| 1956 |
+
"name": "Nilo-Saharan languages"
|
| 1957 |
+
},
|
| 1958 |
+
{
|
| 1959 |
+
"639_1": "ss",
|
| 1960 |
+
"639_2_T": "ssw",
|
| 1961 |
+
"639_2_B": "ssw",
|
| 1962 |
+
"name": "Swati"
|
| 1963 |
+
},
|
| 1964 |
+
{
|
| 1965 |
+
"639_2_T": "suk",
|
| 1966 |
+
"name": "Sukuma"
|
| 1967 |
+
},
|
| 1968 |
+
{
|
| 1969 |
+
"639_1": "su",
|
| 1970 |
+
"639_2_T": "sun",
|
| 1971 |
+
"639_2_B": "sun",
|
| 1972 |
+
"name": "Sundanese"
|
| 1973 |
+
},
|
| 1974 |
+
{
|
| 1975 |
+
"639_2_T": "sus",
|
| 1976 |
+
"name": "Susu"
|
| 1977 |
+
},
|
| 1978 |
+
{
|
| 1979 |
+
"639_2_T": "sux",
|
| 1980 |
+
"name": "Sumerian"
|
| 1981 |
+
},
|
| 1982 |
+
{
|
| 1983 |
+
"639_1": "sw",
|
| 1984 |
+
"639_2_T": "swa",
|
| 1985 |
+
"639_2_B": "swa",
|
| 1986 |
+
"name": "Swahili"
|
| 1987 |
+
},
|
| 1988 |
+
{
|
| 1989 |
+
"639_1": "sv",
|
| 1990 |
+
"639_2_T": "swe",
|
| 1991 |
+
"639_2_B": "swe",
|
| 1992 |
+
"name": "Swedish"
|
| 1993 |
+
},
|
| 1994 |
+
{
|
| 1995 |
+
"639_2_T": "syc",
|
| 1996 |
+
"name": "Classical Syriac"
|
| 1997 |
+
},
|
| 1998 |
+
{
|
| 1999 |
+
"639_2_T": "syr",
|
| 2000 |
+
"name": "Syriac"
|
| 2001 |
+
},
|
| 2002 |
+
{
|
| 2003 |
+
"639_1": "ty",
|
| 2004 |
+
"639_2_T": "tah",
|
| 2005 |
+
"639_2_B": "tah",
|
| 2006 |
+
"name": "Tahitian"
|
| 2007 |
+
},
|
| 2008 |
+
{
|
| 2009 |
+
"639_2_T": "tai",
|
| 2010 |
+
"name": "Tai languages"
|
| 2011 |
+
},
|
| 2012 |
+
{
|
| 2013 |
+
"639_1": "ta",
|
| 2014 |
+
"639_2_T": "tam",
|
| 2015 |
+
"639_2_B": "tam",
|
| 2016 |
+
"name": "Tamil"
|
| 2017 |
+
},
|
| 2018 |
+
{
|
| 2019 |
+
"639_1": "tt",
|
| 2020 |
+
"639_2_T": "tat",
|
| 2021 |
+
"639_2_B": "tat",
|
| 2022 |
+
"name": "Tatar"
|
| 2023 |
+
},
|
| 2024 |
+
{
|
| 2025 |
+
"639_1": "te",
|
| 2026 |
+
"639_2_T": "tel",
|
| 2027 |
+
"639_2_B": "tel",
|
| 2028 |
+
"name": "Telugu"
|
| 2029 |
+
},
|
| 2030 |
+
{
|
| 2031 |
+
"639_2_T": "tem",
|
| 2032 |
+
"name": "Timne"
|
| 2033 |
+
},
|
| 2034 |
+
{
|
| 2035 |
+
"639_2_T": "ter",
|
| 2036 |
+
"name": "Tereno"
|
| 2037 |
+
},
|
| 2038 |
+
{
|
| 2039 |
+
"639_2_T": "tet",
|
| 2040 |
+
"name": "Tetum"
|
| 2041 |
+
},
|
| 2042 |
+
{
|
| 2043 |
+
"639_1": "tg",
|
| 2044 |
+
"639_2_T": "tgk",
|
| 2045 |
+
"639_2_B": "tgk",
|
| 2046 |
+
"name": "Tajik"
|
| 2047 |
+
},
|
| 2048 |
+
{
|
| 2049 |
+
"639_1": "tl",
|
| 2050 |
+
"639_2_T": "tgl",
|
| 2051 |
+
"639_2_B": "tgl",
|
| 2052 |
+
"name": "Tagalog"
|
| 2053 |
+
},
|
| 2054 |
+
{
|
| 2055 |
+
"639_1": "th",
|
| 2056 |
+
"639_2_T": "tha",
|
| 2057 |
+
"639_2_B": "tha",
|
| 2058 |
+
"name": "Thai"
|
| 2059 |
+
},
|
| 2060 |
+
{
|
| 2061 |
+
"639_2_T": "tig",
|
| 2062 |
+
"name": "Tigre"
|
| 2063 |
+
},
|
| 2064 |
+
{
|
| 2065 |
+
"639_1": "ti",
|
| 2066 |
+
"639_2_T": "tir",
|
| 2067 |
+
"639_2_B": "tir",
|
| 2068 |
+
"name": "Tigrinya"
|
| 2069 |
+
},
|
| 2070 |
+
{
|
| 2071 |
+
"639_2_T": "tiv",
|
| 2072 |
+
"name": "Tiv"
|
| 2073 |
+
},
|
| 2074 |
+
{
|
| 2075 |
+
"639_2_T": "tkl",
|
| 2076 |
+
"name": "Tokelau"
|
| 2077 |
+
},
|
| 2078 |
+
{
|
| 2079 |
+
"639_2_T": "tlh",
|
| 2080 |
+
"name": "Klingon; tlhIngan-Hol"
|
| 2081 |
+
},
|
| 2082 |
+
{
|
| 2083 |
+
"639_2_T": "tli",
|
| 2084 |
+
"name": "Tlingit"
|
| 2085 |
+
},
|
| 2086 |
+
{
|
| 2087 |
+
"639_2_T": "tmh",
|
| 2088 |
+
"name": "Tamashek"
|
| 2089 |
+
},
|
| 2090 |
+
{
|
| 2091 |
+
"639_2_T": "tog",
|
| 2092 |
+
"name": "Tonga (Nyasa)"
|
| 2093 |
+
},
|
| 2094 |
+
{
|
| 2095 |
+
"639_1": "to",
|
| 2096 |
+
"639_2_T": "ton",
|
| 2097 |
+
"639_2_B": "ton",
|
| 2098 |
+
"name": "Tonga (Tonga Islands)"
|
| 2099 |
+
},
|
| 2100 |
+
{
|
| 2101 |
+
"639_2_T": "tpi",
|
| 2102 |
+
"name": "Tok Pisin"
|
| 2103 |
+
},
|
| 2104 |
+
{
|
| 2105 |
+
"639_2_T": "tsi",
|
| 2106 |
+
"name": "Tsimshian"
|
| 2107 |
+
},
|
| 2108 |
+
{
|
| 2109 |
+
"639_1": "tn",
|
| 2110 |
+
"639_2_T": "tsn",
|
| 2111 |
+
"639_2_B": "tsn",
|
| 2112 |
+
"name": "Tswana"
|
| 2113 |
+
},
|
| 2114 |
+
{
|
| 2115 |
+
"639_1": "ts",
|
| 2116 |
+
"639_2_T": "tso",
|
| 2117 |
+
"639_2_B": "tso",
|
| 2118 |
+
"name": "Tsonga"
|
| 2119 |
+
},
|
| 2120 |
+
{
|
| 2121 |
+
"639_1": "tk",
|
| 2122 |
+
"639_2_T": "tuk",
|
| 2123 |
+
"639_2_B": "tuk",
|
| 2124 |
+
"name": "Turkmen"
|
| 2125 |
+
},
|
| 2126 |
+
{
|
| 2127 |
+
"639_2_T": "tum",
|
| 2128 |
+
"name": "Tumbuka"
|
| 2129 |
+
},
|
| 2130 |
+
{
|
| 2131 |
+
"639_2_T": "tup",
|
| 2132 |
+
"name": "Tupi languages"
|
| 2133 |
+
},
|
| 2134 |
+
{
|
| 2135 |
+
"639_1": "tr",
|
| 2136 |
+
"639_2_T": "tur",
|
| 2137 |
+
"639_2_B": "tur",
|
| 2138 |
+
"name": "Turkish"
|
| 2139 |
+
},
|
| 2140 |
+
{
|
| 2141 |
+
"639_2_T": "tut",
|
| 2142 |
+
"name": "Altaic languages"
|
| 2143 |
+
},
|
| 2144 |
+
{
|
| 2145 |
+
"639_2_T": "tvl",
|
| 2146 |
+
"name": "Tuvalu"
|
| 2147 |
+
},
|
| 2148 |
+
{
|
| 2149 |
+
"639_1": "tw",
|
| 2150 |
+
"639_2_T": "twi",
|
| 2151 |
+
"639_2_B": "twi",
|
| 2152 |
+
"name": "Twi"
|
| 2153 |
+
},
|
| 2154 |
+
{
|
| 2155 |
+
"639_2_T": "tyv",
|
| 2156 |
+
"name": "Tuvinian"
|
| 2157 |
+
},
|
| 2158 |
+
{
|
| 2159 |
+
"639_2_T": "udm",
|
| 2160 |
+
"name": "Udmurt"
|
| 2161 |
+
},
|
| 2162 |
+
{
|
| 2163 |
+
"639_2_T": "uga",
|
| 2164 |
+
"name": "Ugaritic"
|
| 2165 |
+
},
|
| 2166 |
+
{
|
| 2167 |
+
"639_1": "ug",
|
| 2168 |
+
"639_2_T": "uig",
|
| 2169 |
+
"639_2_B": "uig",
|
| 2170 |
+
"name": "Uighur, Uyghur"
|
| 2171 |
+
},
|
| 2172 |
+
{
|
| 2173 |
+
"639_1": "uk",
|
| 2174 |
+
"639_2_T": "ukr",
|
| 2175 |
+
"639_2_B": "ukr",
|
| 2176 |
+
"name": "Ukrainian"
|
| 2177 |
+
},
|
| 2178 |
+
{
|
| 2179 |
+
"639_2_T": "umb",
|
| 2180 |
+
"name": "Umbundu"
|
| 2181 |
+
},
|
| 2182 |
+
{
|
| 2183 |
+
"639_2_T": "und",
|
| 2184 |
+
"name": "Undetermined"
|
| 2185 |
+
},
|
| 2186 |
+
{
|
| 2187 |
+
"639_1": "ur",
|
| 2188 |
+
"639_2_T": "urd",
|
| 2189 |
+
"639_2_B": "urd",
|
| 2190 |
+
"name": "Urdu"
|
| 2191 |
+
},
|
| 2192 |
+
{
|
| 2193 |
+
"639_1": "uz",
|
| 2194 |
+
"639_2_T": "uzb",
|
| 2195 |
+
"639_2_B": "uzb",
|
| 2196 |
+
"name": "Uzbek"
|
| 2197 |
+
},
|
| 2198 |
+
{
|
| 2199 |
+
"639_2_T": "vai",
|
| 2200 |
+
"name": "Vai"
|
| 2201 |
+
},
|
| 2202 |
+
{
|
| 2203 |
+
"639_1": "ve",
|
| 2204 |
+
"639_2_T": "ven",
|
| 2205 |
+
"639_2_B": "ven",
|
| 2206 |
+
"name": "Venda"
|
| 2207 |
+
},
|
| 2208 |
+
{
|
| 2209 |
+
"639_1": "vi",
|
| 2210 |
+
"639_2_T": "vie",
|
| 2211 |
+
"639_2_B": "vie",
|
| 2212 |
+
"name": "Vietnamese"
|
| 2213 |
+
},
|
| 2214 |
+
{
|
| 2215 |
+
"639_1": "vo",
|
| 2216 |
+
"639_2_T": "vol",
|
| 2217 |
+
"639_2_B": "vol",
|
| 2218 |
+
"name": "Volapük"
|
| 2219 |
+
},
|
| 2220 |
+
{
|
| 2221 |
+
"639_2_T": "vot",
|
| 2222 |
+
"name": "Votic"
|
| 2223 |
+
},
|
| 2224 |
+
{
|
| 2225 |
+
"639_2_T": "wak",
|
| 2226 |
+
"name": "Wakashan languages"
|
| 2227 |
+
},
|
| 2228 |
+
{
|
| 2229 |
+
"639_2_T": "wal",
|
| 2230 |
+
"name": "Wolaitta; Wolaytta"
|
| 2231 |
+
},
|
| 2232 |
+
{
|
| 2233 |
+
"639_2_T": "war",
|
| 2234 |
+
"name": "Waray"
|
| 2235 |
+
},
|
| 2236 |
+
{
|
| 2237 |
+
"639_2_T": "was",
|
| 2238 |
+
"name": "Washo"
|
| 2239 |
+
},
|
| 2240 |
+
{
|
| 2241 |
+
"639_2_T": "wen",
|
| 2242 |
+
"name": "Sorbian languages"
|
| 2243 |
+
},
|
| 2244 |
+
{
|
| 2245 |
+
"639_1": "wa",
|
| 2246 |
+
"639_2_T": "wln",
|
| 2247 |
+
"639_2_B": "wln",
|
| 2248 |
+
"name": "Walloon"
|
| 2249 |
+
},
|
| 2250 |
+
{
|
| 2251 |
+
"639_1": "wo",
|
| 2252 |
+
"639_2_T": "wol",
|
| 2253 |
+
"639_2_B": "wol",
|
| 2254 |
+
"name": "Wolof"
|
| 2255 |
+
},
|
| 2256 |
+
{
|
| 2257 |
+
"639_2_T": "xal",
|
| 2258 |
+
"name": "Kalmyk; Oirat"
|
| 2259 |
+
},
|
| 2260 |
+
{
|
| 2261 |
+
"639_1": "xh",
|
| 2262 |
+
"639_2_T": "xho",
|
| 2263 |
+
"639_2_B": "xho",
|
| 2264 |
+
"name": "Xhosa"
|
| 2265 |
+
},
|
| 2266 |
+
{
|
| 2267 |
+
"639_2_T": "yao",
|
| 2268 |
+
"name": "Yao"
|
| 2269 |
+
},
|
| 2270 |
+
{
|
| 2271 |
+
"639_2_T": "yap",
|
| 2272 |
+
"name": "Yapese"
|
| 2273 |
+
},
|
| 2274 |
+
{
|
| 2275 |
+
"639_1": "yi",
|
| 2276 |
+
"639_2_T": "yid",
|
| 2277 |
+
"639_2_B": "yid",
|
| 2278 |
+
"name": "Yiddish"
|
| 2279 |
+
},
|
| 2280 |
+
{
|
| 2281 |
+
"639_1": "yo",
|
| 2282 |
+
"639_2_T": "yor",
|
| 2283 |
+
"639_2_B": "yor",
|
| 2284 |
+
"name": "Yoruba"
|
| 2285 |
+
},
|
| 2286 |
+
{
|
| 2287 |
+
"639_2_T": "ypk",
|
| 2288 |
+
"name": "Yupik languages"
|
| 2289 |
+
},
|
| 2290 |
+
{
|
| 2291 |
+
"639_2_T": "zap",
|
| 2292 |
+
"name": "Zapotec"
|
| 2293 |
+
},
|
| 2294 |
+
{
|
| 2295 |
+
"639_2_T": "zbl",
|
| 2296 |
+
"name": "Blissymbols; Blissymbolics; Bliss"
|
| 2297 |
+
},
|
| 2298 |
+
{
|
| 2299 |
+
"639_2_T": "zen",
|
| 2300 |
+
"name": "Zenaga"
|
| 2301 |
+
},
|
| 2302 |
+
{
|
| 2303 |
+
"639_2_T": "zgh",
|
| 2304 |
+
"name": "Standard Moroccan Tamazight"
|
| 2305 |
+
},
|
| 2306 |
+
{
|
| 2307 |
+
"639_1": "za",
|
| 2308 |
+
"639_2_T": "zha",
|
| 2309 |
+
"639_2_B": "zha",
|
| 2310 |
+
"name": "Zhuang, Chuang"
|
| 2311 |
+
},
|
| 2312 |
+
{
|
| 2313 |
+
"639_1": "zh",
|
| 2314 |
+
"639_2_T": "zho",
|
| 2315 |
+
"639_2_B": "chi",
|
| 2316 |
+
"name": "Chinese"
|
| 2317 |
+
},
|
| 2318 |
+
{
|
| 2319 |
+
"639_2_T": "znd",
|
| 2320 |
+
"name": "Zande languages"
|
| 2321 |
+
},
|
| 2322 |
+
{
|
| 2323 |
+
"639_1": "zu",
|
| 2324 |
+
"639_2_T": "zul",
|
| 2325 |
+
"639_2_B": "zul",
|
| 2326 |
+
"name": "Zulu"
|
| 2327 |
+
},
|
| 2328 |
+
{
|
| 2329 |
+
"639_2_T": "zun",
|
| 2330 |
+
"name": "Zuni"
|
| 2331 |
+
},
|
| 2332 |
+
{
|
| 2333 |
+
"639_2_T": "zxx",
|
| 2334 |
+
"name": "No linguistic content; Not applicable"
|
| 2335 |
+
},
|
| 2336 |
+
{
|
| 2337 |
+
"639_2_T": "zza",
|
| 2338 |
+
"name": "Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki"
|
| 2339 |
+
}
|
| 2340 |
+
];
|
| 2341 |
+
|
| 2342 |
+
|
| 2343 |
+
return {
|
| 2344 |
+
/**
|
| 2345 |
+
* @param code country code corresponding to alpha2, alpha3 or numeric3
|
| 2346 |
+
* @returns {name: String, 639 codes: String}
|
| 2347 |
+
*/
|
| 2348 |
+
lookup: function (code) {
|
| 2349 |
+
if (!code) {
|
| 2350 |
+
return;
|
| 2351 |
+
}
|
| 2352 |
+
const codeLower = String(code).toLowerCase();
|
| 2353 |
+
for (let i = 0; i < codes.length; i++) {
|
| 2354 |
+
const codeMap = codes[i];
|
| 2355 |
+
|
| 2356 |
+
if (codeLower === codeMap["639_1"] || codeLower === codeMap["639_2_T"] || codeLower === codeMap["639_2_B"]) {
|
| 2357 |
+
return codeMap;
|
| 2358 |
+
}
|
| 2359 |
+
}
|
| 2360 |
+
}
|
| 2361 |
+
}
|
| 2362 |
+
}());
|
js/randojs-2.0.0.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// https://github.com/nastyox/Rando.js
|
| 2 |
+
function rando(a,b,e){var g=function(f){return"undefined"===typeof f},k=function(f){return"number"===typeof f&&!isNaN(f)},d=function(f){return!g(f)&&null!==f&&f.constructor===Array},c=function(){try{for(var f,q=[],r;30>(r="."+q.join("")).length;){f=(window.crypto||window.msCrypto).getRandomValues(new Uint32Array(5));for(var p=0;p<f.length;p++){var t=4E9>f[p]?f[p].toString().slice(1):"";0<t.length&&(q[q.length]=t)}}return Number(r)}catch(v){return Math.random()}};try{if(null!==a&&null!==b&&null!==
|
| 3 |
+
e){if(g(a))return c();if(window.jQuery&&a instanceof jQuery&&g(b)){if(0==a.length)return!1;var n=rando(0,a.length-1);return{index:n,value:a.eq(n)}}if(k(a)&&k(b)&&"string"===typeof e&&"float"==e.toLowerCase().trim()){if(a>b){var m=b;b=a;a=m}return c()*(b-a)+a}if(d(a)&&0<a.length&&g(b)){var l=c()*a.length<<0;return{index:l,value:a[l]}}if("object"===typeof a&&g(b)){l=a;var h=Object.keys(l);if(0<h.length){var u=h[h.length*c()<<0];return{key:u,value:l[u]}}}if((!0===a&&!1===b||!1===a&&!0===b)&&g(e))return.5>
|
| 4 |
+
rando();if(k(a)&&g(b))return 0<=a?rando(0,a):rando(a,0);if(k(a)&&"string"===typeof b&&"float"==b.toLowerCase().trim()&&g(e))return 0<=a?rando(0,a,"float"):rando(a,0,"float");if(k(a)&&k(b)&&g(e))return a>b&&(m=b,b=a,a=m),a=Math.floor(a),b=Math.floor(b),Math.floor(c()*(b-a+1)+a);if("string"===typeof a&&0<a.length&&g(b))return a.charAt(rando(0,a.length-1))}return!1}catch(f){return!1}}
|
| 5 |
+
function randoSequence(a,b){var e=function(h){return"undefined"===typeof h},g=function(h){return"number"===typeof h&&!isNaN(h)},k=function(h){return!e(h)&&null!==h&&h.constructor===Array};try{if(e(a)||null===a||null===b)return!1;var d=[];if(window.jQuery&&a instanceof jQuery&&e(b)){if(0<a.length){d=randoSequence(0,a.length-1);for(var c=0;c<d.length;c++)d[c]={index:d[c],value:a.eq(d[c])}}return d}if(e(b))if(k(a)&&e(b))for(c=0;c<a.length;c++)d[d.length]={index:c,value:a[c]};else if("object"===typeof a&&
|
| 6 |
+
e(b))for(var n in a)Object.prototype.hasOwnProperty.call(a,n)&&(d[d.length]={key:n,value:a[n]});else if("string"===typeof a&&e(b))for(c=0;c<a.length;c++)d[d.length]=a.charAt(c);else return g(a)&&e(b)?0<=a?randoSequence(0,a):randoSequence(a,0):!1;else{if(!g(a)||!g(b)||0<a%1||0<b%1)return!1;if(a>b){var m=b;b=a;a=m}for(c=a;c<=b;c++)d[d.length]=c}for(c=d.length-1;0<c;c--){var l=rando(c);m=d[c];d[c]=d[l];d[l]=m}return d}catch(h){return!1}};
|
js/shared.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Shared methods for normal & bulk pages.
|
| 3 |
+
*/
|
| 4 |
+
const shared = (function () {
|
| 5 |
+
'use strict';
|
| 6 |
+
|
| 7 |
+
const patterns = {
|
| 8 |
+
video_id: [
|
| 9 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/watch\?v=([\w_-]+)(?:[\/&].*)?/i,
|
| 10 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/(?:v|embed|shorts|video|watch|live)\/([\w_-]+)(?:[\/&].*)?/i,
|
| 11 |
+
/(?:http[s]?:\/\/)?youtu.be\/([\w_-]+)(?:\?.*)?/i,
|
| 12 |
+
/(?:http[s]?:\/\/)?filmot.com\/video\/([\w_-]+)(?:[?\/&].*)?/i,
|
| 13 |
+
/(?:http[s]?:\/\/)?filmot.com\/sidebyside\/([\w_-]+)(?:[?\/&].*)?/i,
|
| 14 |
+
/^([\w-]{11})$/i
|
| 15 |
+
],
|
| 16 |
+
playlist_id: [
|
| 17 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/playlist\?list=([\w_-]+)(?:&.*)?/i,
|
| 18 |
+
/^((UU|UUSH|PL|FL|SP|OLAK)[A-Za-z0-9_-]+)$/i
|
| 19 |
+
],
|
| 20 |
+
channel_id: [
|
| 21 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/channel\/([\w_-]+)(?:\?.*)?/i,
|
| 22 |
+
/(?:http[s]?:\/\/)?filmot.com\/channel\/([\w_-]+)(?:[?\/&].*)?/i,
|
| 23 |
+
/^((UC|SC)[\w-]{22})$/i
|
| 24 |
+
],
|
| 25 |
+
channel_user: [
|
| 26 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/user\/([\w_-]+)(?:\?.*)?/i
|
| 27 |
+
],
|
| 28 |
+
channel_handle: [
|
| 29 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/@([^\/?]+)(?:\?.*)?/i,
|
| 30 |
+
],
|
| 31 |
+
channel_custom: [
|
| 32 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/c\/([^\/?]+)(?:\?.*)?/i,
|
| 33 |
+
/(?:http[s]?:\/\/)?(?:\w+\.)?youtube.com\/([^\/?]+)(?:\?.*)?/i
|
| 34 |
+
]
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
return {
|
| 38 |
+
/**
|
| 39 |
+
* Safely get nested object property or returns null
|
| 40 |
+
*/
|
| 41 |
+
idx: (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o),
|
| 42 |
+
|
| 43 |
+
determineInput: function (value) {
|
| 44 |
+
value = decodeURIComponent(value);
|
| 45 |
+
const parsed = {
|
| 46 |
+
type: 'unknown',
|
| 47 |
+
mayHideOthers: true,
|
| 48 |
+
original: value
|
| 49 |
+
};
|
| 50 |
+
for (let type in patterns) {
|
| 51 |
+
for (let i = 0; i < patterns[type].length; i++) {
|
| 52 |
+
const regex = patterns[type][i];
|
| 53 |
+
const result = regex.exec(value);
|
| 54 |
+
|
| 55 |
+
if (result) {
|
| 56 |
+
parsed.type = type;
|
| 57 |
+
parsed.value = result[1];
|
| 58 |
+
return parsed;
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
return parsed;
|
| 63 |
+
},
|
| 64 |
+
|
| 65 |
+
// https://wiki.archiveteam.org/index.php/YouTube/Technical_details
|
| 66 |
+
isValidVideoId: function (videoId) {
|
| 67 |
+
return videoId !== undefined && videoId !== null &&
|
| 68 |
+
String(videoId).match(/[A-Za-z0-9_-]{10}[AEIMQUYcgkosw048]/);
|
| 69 |
+
},
|
| 70 |
+
|
| 71 |
+
isValidChannelId: function (channelId) {
|
| 72 |
+
return channelId !== undefined && channelId !== null &&
|
| 73 |
+
String(channelId).match(/[A-Za-z0-9_-]{21}[AQgw]/);
|
| 74 |
+
},
|
| 75 |
+
|
| 76 |
+
parseQuery: function (queryString) {
|
| 77 |
+
const query = {};
|
| 78 |
+
const pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
|
| 79 |
+
for (let i = 0; i < pairs.length; i++) {
|
| 80 |
+
let pair = pairs[i].split('=');
|
| 81 |
+
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
|
| 82 |
+
}
|
| 83 |
+
return query;
|
| 84 |
+
},
|
| 85 |
+
|
| 86 |
+
formatDuration: function (duration, includeMs, ignoreTime) {
|
| 87 |
+
const years = duration.years();
|
| 88 |
+
const months = duration.months();
|
| 89 |
+
const days = duration.days();
|
| 90 |
+
const hours = duration.hours();
|
| 91 |
+
const minutes = duration.minutes();
|
| 92 |
+
const seconds = duration.seconds();
|
| 93 |
+
const millis = duration.milliseconds();
|
| 94 |
+
const format = [
|
| 95 |
+
(years > 0 ? years + " years" : ""),
|
| 96 |
+
(months > 0 ? months + " months" : ""),
|
| 97 |
+
(days > 0 ? days + " days" : ""),
|
| 98 |
+
(!ignoreTime && hours > 0 ? hours + "h" : ""),
|
| 99 |
+
(!ignoreTime && minutes > 0 ? minutes + "m" : ""),
|
| 100 |
+
(!ignoreTime && seconds > 0 ? seconds + "s" : ""),
|
| 101 |
+
includeMs ? (millis > 0 ? millis + "ms" : "") : ""
|
| 102 |
+
].join(" ");
|
| 103 |
+
|
| 104 |
+
if (format.trim() === "") {
|
| 105 |
+
return "0s";
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
return format;
|
| 109 |
+
},
|
| 110 |
+
|
| 111 |
+
sortObject: function (unordered, sortArrays = false) {
|
| 112 |
+
if (!unordered || typeof unordered !== 'object') {
|
| 113 |
+
return unordered;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
if (Array.isArray(unordered)) {
|
| 117 |
+
const newArr = unordered.map((item) => this.sortObject(item, sortArrays));
|
| 118 |
+
if (sortArrays) {
|
| 119 |
+
newArr.sort();
|
| 120 |
+
}
|
| 121 |
+
return newArr;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
const ordered = {};
|
| 125 |
+
Object.keys(unordered)
|
| 126 |
+
.sort()
|
| 127 |
+
.forEach((key) => {
|
| 128 |
+
ordered[key] = this.sortObject(unordered[key], sortArrays);
|
| 129 |
+
});
|
| 130 |
+
return ordered;
|
| 131 |
+
},
|
| 132 |
+
|
| 133 |
+
safeFileName: function (fileName) {
|
| 134 |
+
return fileName.replace(/[<>:"\/\\|?*]+/g, '');
|
| 135 |
+
},
|
| 136 |
+
|
| 137 |
+
randomFromList(list) {
|
| 138 |
+
let index = 0;
|
| 139 |
+
for (let i = 0; i < 5; i++) {
|
| 140 |
+
index = rando(0, list.length - 1);
|
| 141 |
+
}
|
| 142 |
+
return list[index];
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
+
})();
|
js/youtube-api-v3.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* YouTube API v3
|
| 3 |
+
* Reference documentation:
|
| 4 |
+
* https://developers.google.com/youtube/v3/docs/
|
| 5 |
+
*
|
| 6 |
+
* youtube.ajax("videos", {
|
| 7 |
+
* part: 'snippet'
|
| 8 |
+
* }).done(function (res) {
|
| 9 |
+
*
|
| 10 |
+
* }).fail(function (err) {
|
| 11 |
+
*
|
| 12 |
+
* });
|
| 13 |
+
*
|
| 14 |
+
* @requires jquery
|
| 15 |
+
* @author mattwright324
|
| 16 |
+
*/
|
| 17 |
+
const youtube = (function ($) {
|
| 18 |
+
'use strict';
|
| 19 |
+
|
| 20 |
+
function makeStr(length) {
|
| 21 |
+
let result = '';
|
| 22 |
+
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
| 23 |
+
const charactersLength = characters.length;
|
| 24 |
+
let counter = 0;
|
| 25 |
+
while (counter < length) {
|
| 26 |
+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
| 27 |
+
counter += 1;
|
| 28 |
+
}
|
| 29 |
+
return result;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
const tempId = localStorage.getItem("tempId") || makeStr(40);
|
| 33 |
+
localStorage.setItem("tempId", tempId);
|
| 34 |
+
|
| 35 |
+
let defaultKey = "";
|
| 36 |
+
let currentKey = "";
|
| 37 |
+
|
| 38 |
+
return {
|
| 39 |
+
setDefaultKey: function (key) {
|
| 40 |
+
defaultKey = key;
|
| 41 |
+
this.setKey(key);
|
| 42 |
+
},
|
| 43 |
+
getDefaultKey: function () {
|
| 44 |
+
return defaultKey;
|
| 45 |
+
},
|
| 46 |
+
setKey: function (key) {
|
| 47 |
+
if (defaultKey === "") {
|
| 48 |
+
this.setDefaultKey(key);
|
| 49 |
+
}
|
| 50 |
+
currentKey = key;
|
| 51 |
+
},
|
| 52 |
+
getKey: function () {
|
| 53 |
+
return currentKey;
|
| 54 |
+
},
|
| 55 |
+
ajax: function (type, data) {
|
| 56 |
+
if (!defaultKey && defaultKey === "" && !currentKey && currentKey === "") {
|
| 57 |
+
console.error("YouTube API Key Missing");
|
| 58 |
+
} else {
|
| 59 |
+
return $.ajax({
|
| 60 |
+
cache: false,
|
| 61 |
+
data: $.extend({key: currentKey, quotaUser: tempId}, data),
|
| 62 |
+
dataType: "json",
|
| 63 |
+
type: "GET",
|
| 64 |
+
timeout: 5000,
|
| 65 |
+
url: "https://www.googleapis.com/youtube/v3/" + type
|
| 66 |
+
});
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
};
|
| 70 |
+
}($));
|
| 71 |
+
youtube.setDefaultKey(atob('QUl6YVN5QVNUTVFjay1qdHRGOHF5OXJ0RW50MUh5RVl3NUFtaEU4'));
|
js/youtube-metadata-bulk.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
js/youtube-metadata-examples.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
js/youtube-metadata.js
ADDED
|
@@ -0,0 +1,1868 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* YouTube Metadata
|
| 3 |
+
*
|
| 4 |
+
* Grab everything publicly available from the YouTube API.
|
| 5 |
+
*
|
| 6 |
+
* @requires jquery
|
| 7 |
+
* @author mattwright324
|
| 8 |
+
*/
|
| 9 |
+
(function () {
|
| 10 |
+
'use strict';
|
| 11 |
+
|
| 12 |
+
const elements = {};
|
| 13 |
+
const controls = {};
|
| 14 |
+
let exportData = {};
|
| 15 |
+
|
| 16 |
+
const delaySubmitKey = "delaySubmitNormal";
|
| 17 |
+
const can = {
|
| 18 |
+
submit: true,
|
| 19 |
+
};
|
| 20 |
+
|
| 21 |
+
const delay5Sec = 5;
|
| 22 |
+
const delay5SecMs = delay5Sec * 1000;
|
| 23 |
+
|
| 24 |
+
function countdown(key, control, delay, flag) {
|
| 25 |
+
control.addClass("loading").addClass("disabled");
|
| 26 |
+
can[flag] = false;
|
| 27 |
+
|
| 28 |
+
let value = localStorage.getItem(key);
|
| 29 |
+
if (!moment(value).isValid()) {
|
| 30 |
+
console.warn('value for %s was not a valid date, resetting to now', key);
|
| 31 |
+
localStorage.setItem(key, new Date());
|
| 32 |
+
value = localStorage.getItem(key);
|
| 33 |
+
}
|
| 34 |
+
if (moment(value).isAfter(moment())) {
|
| 35 |
+
console.warn('value for %s was set in the future, resetting to now', key);
|
| 36 |
+
localStorage.setItem(key, new Date());
|
| 37 |
+
value = localStorage.getItem(key);
|
| 38 |
+
}
|
| 39 |
+
let count = (delay - moment().diff(value)) / 1000;
|
| 40 |
+
control.find(".countdown").text(Math.trunc(count));
|
| 41 |
+
|
| 42 |
+
function c(control, count) {
|
| 43 |
+
if (count <= 1) {
|
| 44 |
+
control.removeClass("loading").removeClass("disabled");
|
| 45 |
+
control.find(".countdown").text("");
|
| 46 |
+
|
| 47 |
+
can[flag] = true;
|
| 48 |
+
} else {
|
| 49 |
+
control.find(".countdown").text(Math.trunc(count));
|
| 50 |
+
setTimeout(function () {
|
| 51 |
+
c(control, count - 1)
|
| 52 |
+
}, 1000);
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
setTimeout(function () {
|
| 57 |
+
c(control, count)
|
| 58 |
+
}, 1000);
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
function countdownCheck(key, control, delayMs, flag) {
|
| 62 |
+
const value = localStorage.getItem(key);
|
| 63 |
+
if (key in localStorage && moment(value).isValid() && moment().diff(value) < delayMs) {
|
| 64 |
+
countdown(key, control, delayMs, flag);
|
| 65 |
+
} else {
|
| 66 |
+
control.removeClass("loading").removeClass("disabled");
|
| 67 |
+
control.find(".countdown").text("");
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
function getSuggestedHtml(parsedInput, fullJson, jsonType, filmot) {
|
| 71 |
+
const suggested = getSuggestedLinks(parsedInput, fullJson, jsonType, filmot);
|
| 72 |
+
suggested.sort((a, b) => (a.text > b.text) ? 1 : -1)
|
| 73 |
+
const html = [];
|
| 74 |
+
for (let i = 0; i < suggested.length; i++) {
|
| 75 |
+
const link = suggested[i];
|
| 76 |
+
html.push("<li><a target='_blank' href='" + link.url + "'>" + link.text + "</a></li>")
|
| 77 |
+
}
|
| 78 |
+
return "<ul>" + html.join("") + "</ul>";
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
function getConvertTime(date) {
|
| 82 |
+
const momentTime = moment(date).utc();
|
| 83 |
+
|
| 84 |
+
return " (<a target='_blank' href='https://www.timeanddate.com/worldclock/converter.html?iso=" +
|
| 85 |
+
momentTime.format("YYYYMMDDTHHmmss") + "'>convert</a>)"
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
function getSuggestedLinks(parsedInput, fullJson, jsonType, filmot) {
|
| 89 |
+
const data = {}
|
| 90 |
+
if (parsedInput) {
|
| 91 |
+
data[parsedInput.type] = parsedInput.value;
|
| 92 |
+
} else if (fullJson) {
|
| 93 |
+
if (jsonType === "video") {
|
| 94 |
+
data["video_id"] = fullJson.id;
|
| 95 |
+
data["video_title"] = shared.idx(["snippet", "title"], fullJson);
|
| 96 |
+
data["test"] = "test";
|
| 97 |
+
} else if (jsonType === "playlist") {
|
| 98 |
+
data["playlist_id"] = fullJson.id;
|
| 99 |
+
data["playlist_title"] = shared.idx(["snippet", "title"], fullJson);
|
| 100 |
+
} else if (jsonType === "channel") {
|
| 101 |
+
data["channel_id"] = fullJson.id;
|
| 102 |
+
data["channel_title"] = shared.idx(["snippet", "title"], fullJson);
|
| 103 |
+
|
| 104 |
+
const custom = shared.idx(["snippet", "customUrl"], fullJson);
|
| 105 |
+
if (custom) {
|
| 106 |
+
data["channel_custom"] = custom;
|
| 107 |
+
}
|
| 108 |
+
}
|
| 109 |
+
} else if (filmot) {
|
| 110 |
+
data["video_title"] = filmot.title;
|
| 111 |
+
data["channel_id"] = filmot.channelid;
|
| 112 |
+
data["channel_title"] = filmot.channelname;
|
| 113 |
+
}
|
| 114 |
+
console.log(data);
|
| 115 |
+
|
| 116 |
+
function encode(text) {
|
| 117 |
+
return encodeURIComponent(text).replace(/'/g, "%27");
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
const suggestions = [];
|
| 121 |
+
if (data.hasOwnProperty("video_title")) {
|
| 122 |
+
suggestions.push({
|
| 123 |
+
url: "https://www.google.com/search?q=\"" + encode(data.video_title) + "\"",
|
| 124 |
+
text: "Google - \"" + data.video_title + "\""
|
| 125 |
+
});
|
| 126 |
+
suggestions.push({
|
| 127 |
+
url: "https://archive.org/search.php?query=" + encode(data.video_title),
|
| 128 |
+
text: "Archive.org (search) - " + data.video_title
|
| 129 |
+
});
|
| 130 |
+
}
|
| 131 |
+
if (data.hasOwnProperty("video_id")) {
|
| 132 |
+
suggestions.push({
|
| 133 |
+
url: "https://www.google.com/search?q=\"" + data.video_id + "\"",
|
| 134 |
+
text: "Google - \"" + data.video_id + "\""
|
| 135 |
+
});
|
| 136 |
+
suggestions.push({
|
| 137 |
+
url: "https://web.archive.org/web/*/https://www.youtube.com/watch?v=" + data.video_id,
|
| 138 |
+
text: "Archive.org (web) - https://www.youtube.com/watch?v=" + data.video_id
|
| 139 |
+
});
|
| 140 |
+
suggestions.push({
|
| 141 |
+
url: "https://archive.org/details/youtube-" + data.video_id,
|
| 142 |
+
text: "Archive.org (details) - youtube-" + data.video_id
|
| 143 |
+
});
|
| 144 |
+
suggestions.push({
|
| 145 |
+
url: "https://web.archive.org/web/2/http://wayback-fakeurl.archive.org/yt/" + data.video_id,
|
| 146 |
+
text: "Archive.org (direct video wayback-header) - " + data.video_id
|
| 147 |
+
});
|
| 148 |
+
suggestions.push({
|
| 149 |
+
url: "https://web.archive.org/web/2oe_/http://wayback-fakeurl.archive.org/yt/" + data.video_id,
|
| 150 |
+
text: "Archive.org (direct video raw) - " + data.video_id
|
| 151 |
+
});
|
| 152 |
+
suggestions.push({
|
| 153 |
+
url: "https://filmot.com/video/" + data.video_id,
|
| 154 |
+
text: "Filmot.com - https://filmot.com/video/" + data.video_id
|
| 155 |
+
});
|
| 156 |
+
suggestions.push({
|
| 157 |
+
url: "https://ghostarchive.org/varchive/" + data.video_id,
|
| 158 |
+
text: "GhostArchive.org - " + data.video_id
|
| 159 |
+
});
|
| 160 |
+
// suggestions.push({
|
| 161 |
+
// url: "https://www.youtuberecover.com/watch?v=" + data.video_id,
|
| 162 |
+
// text: "YouTube Recover - " + data.video_id
|
| 163 |
+
// });
|
| 164 |
+
suggestions.push({
|
| 165 |
+
url: "https://hobune.stream/videos/" + data.video_id,
|
| 166 |
+
text: "Hobune Archive - " + data.video_id
|
| 167 |
+
});
|
| 168 |
+
}
|
| 169 |
+
if (data.hasOwnProperty("playlist_title")) {
|
| 170 |
+
suggestions.push({
|
| 171 |
+
url: "https://www.google.com/search?q=\"" + encode(data.playlist_title) + "\"",
|
| 172 |
+
text: "Google - \"" + data.playlist_title + "\""
|
| 173 |
+
});
|
| 174 |
+
}
|
| 175 |
+
if (data.hasOwnProperty("playlist_id")) {
|
| 176 |
+
suggestions.push({
|
| 177 |
+
url: "https://www.google.com/search?q=\"" + data.playlist_id + "\"",
|
| 178 |
+
text: "Google - \"" + data.playlist_id + "\""
|
| 179 |
+
});
|
| 180 |
+
suggestions.push({
|
| 181 |
+
url: "https://web.archive.org/web/*/https://www.youtube.com/playlist?list=" + data.playlist_id,
|
| 182 |
+
text: "Archive.org - https://www.youtube.com/playlist?list=" + data.playlist_id
|
| 183 |
+
});
|
| 184 |
+
}
|
| 185 |
+
if (data.hasOwnProperty("channel_title")) {
|
| 186 |
+
suggestions.push({
|
| 187 |
+
url: "https://www.google.com/search?q=\"" + encode(data.channel_title) + "\"",
|
| 188 |
+
text: "Google - \"" + data.channel_title + "\""
|
| 189 |
+
});
|
| 190 |
+
suggestions.push({
|
| 191 |
+
url: "https://archive.org/search.php?query=creator%3A%22" + encode(data.channel_title) + "%22",
|
| 192 |
+
text: "Archive.org (search) - creator:\"" + data.channel_title + "\""
|
| 193 |
+
});
|
| 194 |
+
suggestions.push({
|
| 195 |
+
url: "https://archive.org/search.php?query=subject%3A%22" + encode(data.channel_title) + "%22",
|
| 196 |
+
text: "Archive.org (search) - subject:\"" + data.channel_title + "\""
|
| 197 |
+
});
|
| 198 |
+
suggestions.push({
|
| 199 |
+
url: "https://archive.org/search.php?query=" + encode(data.channel_title),
|
| 200 |
+
text: "Archive.org (search) - " + data.channel_title
|
| 201 |
+
});
|
| 202 |
+
}
|
| 203 |
+
if (data.hasOwnProperty("channel_user")) {
|
| 204 |
+
// this can only happen if /user/ no longer exists on submit
|
| 205 |
+
suggestions.push({
|
| 206 |
+
url: "https://www.google.com/search?q=\"" + data.channel_user + "\"",
|
| 207 |
+
text: "Google - \"" + data.channel_user + "\""
|
| 208 |
+
});
|
| 209 |
+
suggestions.push({
|
| 210 |
+
url: "https://web.archive.org/web/*/https://www.youtube.com/user/" + data.channel_user,
|
| 211 |
+
text: "Archive.org - https://www.youtube.com/user/" + data.channel_user
|
| 212 |
+
});
|
| 213 |
+
suggestions.push({
|
| 214 |
+
url: "https://archive.org/search.php?query=subject%3A%22" + encode(data.channel_user) + "%22",
|
| 215 |
+
text: "Archive.org (search) - subject:\"" + data.channel_user + "\""
|
| 216 |
+
});
|
| 217 |
+
suggestions.push({
|
| 218 |
+
url: "https://archive.org/search.php?query=" + data.channel_user,
|
| 219 |
+
text: "Archive.org (search) - " + data.channel_user
|
| 220 |
+
});
|
| 221 |
+
}
|
| 222 |
+
if (data.hasOwnProperty("channel_custom")) {
|
| 223 |
+
// this can only happen in channel-more if user has custom value
|
| 224 |
+
suggestions.push({
|
| 225 |
+
url: "https://www.google.com/search?q=\"" + data.channel_custom + "\"",
|
| 226 |
+
text: "Google - \"" + data.channel_custom + "\""
|
| 227 |
+
});
|
| 228 |
+
if (data.channel_custom.startsWith('@')) {
|
| 229 |
+
suggestions.push({
|
| 230 |
+
url: "https://web.archive.org/web/*/https://www.youtube.com/" + data.channel_custom,
|
| 231 |
+
text: "Archive.org - https://www.youtube.com/" + data.channel_custom
|
| 232 |
+
});
|
| 233 |
+
} else {
|
| 234 |
+
suggestions.push({
|
| 235 |
+
url: "https://web.archive.org/web/*/https://www.youtube.com/c/" + data.channel_custom,
|
| 236 |
+
text: "Archive.org - https://www.youtube.com/c/" + data.channel_custom
|
| 237 |
+
});
|
| 238 |
+
}
|
| 239 |
+
suggestions.push({
|
| 240 |
+
url: "https://web.archive.org/web/*/https://www.youtube.com/" + data.channel_custom,
|
| 241 |
+
text: "Archive.org - https://www.youtube.com/" + data.channel_custom
|
| 242 |
+
});
|
| 243 |
+
suggestions.push({
|
| 244 |
+
url: "https://archive.org/search.php?query=" + data.channel_custom,
|
| 245 |
+
text: "Archive.org (search) - " + data.channel_custom
|
| 246 |
+
});
|
| 247 |
+
}
|
| 248 |
+
if (data.hasOwnProperty("channel_id")) {
|
| 249 |
+
suggestions.push({
|
| 250 |
+
url: "https://www.google.com/search?q=\"" + data.channel_id + "\"",
|
| 251 |
+
text: "Google - \"" + data.channel_id + "\""
|
| 252 |
+
});
|
| 253 |
+
suggestions.push({
|
| 254 |
+
url: "https://web.archive.org/web/*/https://www.youtube.com/channel/" + data.channel_id,
|
| 255 |
+
text: "Archive.org - https://www.youtube.com/channel/" + data.channel_id
|
| 256 |
+
});
|
| 257 |
+
suggestions.push({
|
| 258 |
+
url: "https://archive.org/search.php?query=subject%3A%22" + encode(data.channel_id) + "%22",
|
| 259 |
+
text: "Archive.org (search) - subject:\"" + data.channel_id + "\""
|
| 260 |
+
});
|
| 261 |
+
suggestions.push({
|
| 262 |
+
url: "https://archive.org/search.php?query=" + data.channel_id,
|
| 263 |
+
text: "Archive.org (search) - " + data.channel_id
|
| 264 |
+
});
|
| 265 |
+
suggestions.push({
|
| 266 |
+
url: "https://socialblade.com/youtube/channel/" + data.channel_id,
|
| 267 |
+
text: "Socialblade.com - " + data.channel_id
|
| 268 |
+
})
|
| 269 |
+
suggestions.push({
|
| 270 |
+
url: "https://filmot.com/channel/" + data.channel_id,
|
| 271 |
+
text: "Filmot.com - https://filmot.com/channel/" + data.channel_id
|
| 272 |
+
});
|
| 273 |
+
// suggestions.push({
|
| 274 |
+
// url: "https://www.youtuberecover.com/channel?id=" + data.channel_id,
|
| 275 |
+
// text: "YouTube Recover - " + data.channel_id
|
| 276 |
+
// });
|
| 277 |
+
suggestions.push({
|
| 278 |
+
url: "https://hobune.stream/channels/" + data.channel_id,
|
| 279 |
+
text: "Hobune Archive - " + data.channel_id
|
| 280 |
+
});
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
return suggestions;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
function getDuration(a, b) {
|
| 287 |
+
if (a.isBefore(b)) {
|
| 288 |
+
return moment.duration(b.diff(a));
|
| 289 |
+
} else {
|
| 290 |
+
return moment.duration(a.diff(b));
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
function formatBCP47(translation) {
|
| 295 |
+
const findings = [];
|
| 296 |
+
|
| 297 |
+
if (translation.language) {
|
| 298 |
+
findings.push(translation.language.name);
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
if (translation.country) {
|
| 302 |
+
findings.push(translation.country.name);
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
return findings.join(" / ");
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
function processLocalizations(partDiv, partJson) {
|
| 309 |
+
const translations = [];
|
| 310 |
+
|
| 311 |
+
for (let code in partJson) {
|
| 312 |
+
translations.push("<li><span class='orange'>" + String(code).toUpperCase() + "</span> which is <span class='orange'>" + formatBCP47(bcp47.lookup(code)) + "</span></li>")
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
partDiv.append("<p class='mb-15'>Localizations for..." +
|
| 316 |
+
"<ul>" + translations.join("") + "</ul>" +
|
| 317 |
+
"</p>")
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
function normalize(a, b) {
|
| 321 |
+
let normalizedA = a, normalizedB = b;
|
| 322 |
+
let gcdValue = 0, gcdA = 0, gcdB = 0;
|
| 323 |
+
|
| 324 |
+
if (a > 0 && b > 0) {
|
| 325 |
+
function gcd(p, q) {
|
| 326 |
+
if (q === 0) {
|
| 327 |
+
return p;
|
| 328 |
+
}
|
| 329 |
+
return gcd(q, p % q);
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
gcdValue = gcd(a, b);
|
| 333 |
+
gcdA = gcdValue === 0 ? 0 : a / gcdValue;
|
| 334 |
+
gcdB = gcdValue === 0 ? 0 : b / gcdValue;
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
if (gcdValue !== 0) {
|
| 338 |
+
if (gcdA > gcdB) {
|
| 339 |
+
normalizedA = gcdA / gcdB;
|
| 340 |
+
normalizedB = 1;
|
| 341 |
+
} else {
|
| 342 |
+
normalizedA = 1;
|
| 343 |
+
normalizedB = gcdB / gcdA;
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
return {a: normalizedA, b: normalizedB}
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
const partMap = {
|
| 351 |
+
/**
|
| 352 |
+
* Can't access part(s): fileDetails, processingDetails, suggestions
|
| 353 |
+
* Useless part(s): player, id
|
| 354 |
+
* Every other part below:
|
| 355 |
+
*/
|
| 356 |
+
video: {
|
| 357 |
+
snippet: {
|
| 358 |
+
title: "Snippet",
|
| 359 |
+
postProcess: function (partJson, fullJson) {
|
| 360 |
+
const partDiv = $("#video-section #snippet");
|
| 361 |
+
|
| 362 |
+
const thumbs = partJson.thumbnails;
|
| 363 |
+
const thumbUrl = (thumbs.maxres || thumbs.high || thumbs.medium || thumbs.default || {url: "https://placehold.it/480x360"}).url;
|
| 364 |
+
|
| 365 |
+
partDiv.append("<a target='_blank' href='https://youtu.be/" + fullJson.id + "'><img id='video-thumb' src='" + thumbUrl + "' class='mb-15'></a>");
|
| 366 |
+
|
| 367 |
+
const titleHtml =
|
| 368 |
+
"<p class='mb-15' style='font-size: 1.25em'>" + partJson.title + "</p>";
|
| 369 |
+
partDiv.append(titleHtml);
|
| 370 |
+
|
| 371 |
+
const authorHtml =
|
| 372 |
+
"<p class='mb-15'>Published by " +
|
| 373 |
+
"<a href='https://www.youtube.com/channel/" + partJson.channelId + "' target='_blank'>" +
|
| 374 |
+
partJson.channelTitle +
|
| 375 |
+
"</a>" +
|
| 376 |
+
"</p>";
|
| 377 |
+
partDiv.append(authorHtml);
|
| 378 |
+
|
| 379 |
+
const published = new Date(partJson.publishedAt);
|
| 380 |
+
const dateHtml =
|
| 381 |
+
"<p class='mb-15'>Published on " +
|
| 382 |
+
"<span class='orange'>" + published.toUTCString() + "</span>" +
|
| 383 |
+
" (" + moment(published).utc().fromNow() + ") " + getConvertTime(published) +
|
| 384 |
+
"</p>";
|
| 385 |
+
partDiv.append(dateHtml);
|
| 386 |
+
|
| 387 |
+
if (partJson.tags) {
|
| 388 |
+
const tagsHtml =
|
| 389 |
+
"<p class='mb-15'>Tag(s): " +
|
| 390 |
+
"<span class='tag'>" + partJson.tags.join("</span><span class='comma'>, </span><span class='tag'>") + "</span>" +
|
| 391 |
+
"</p>";
|
| 392 |
+
partDiv.append(tagsHtml);
|
| 393 |
+
} else {
|
| 394 |
+
partDiv.append("<p class='mb-15'>There were no tags.</p>")
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
if (partJson.categoryId) {
|
| 398 |
+
const html =
|
| 399 |
+
"<p class='mb-15'>Category id is " +
|
| 400 |
+
"<span class='orange'>" + partJson.categoryId + "</span> which means " +
|
| 401 |
+
"<span class='orange'>" + ytCategory.lookup(partJson.categoryId) + "</span>" +
|
| 402 |
+
"</p>";
|
| 403 |
+
|
| 404 |
+
partDiv.append(html);
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
if (partJson.defaultLanguage) {
|
| 408 |
+
const code = partJson.defaultLanguage.toUpperCase();
|
| 409 |
+
const translated = bcp47.lookup(code);
|
| 410 |
+
|
| 411 |
+
partDiv.append("<p class='mb-15'>Default language is <span class='orange'>" + code + "</span> which means <span class='orange'>" + formatBCP47(translated) + "</span></p>")
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
if (partJson.defaultAudioLanguage) {
|
| 415 |
+
const code = partJson.defaultAudioLanguage.toUpperCase();
|
| 416 |
+
const translated = bcp47.lookup(code);
|
| 417 |
+
|
| 418 |
+
partDiv.append("<p class='mb-15'>Audio language is <span class='orange'>" + code + "</span> which means <span class='orange'>" + formatBCP47(translated) + "</span></p>")
|
| 419 |
+
}
|
| 420 |
+
|
| 421 |
+
partDiv.append("<p class='mb-15'>The video id is <span class='orange'>" + fullJson.id + "</span></p>");
|
| 422 |
+
|
| 423 |
+
partDiv.append("<p class='mb-15'><a style='display:inline;vertical-align:middle' target='_blank' href='./bulk?submit=true&url=https://www.youtube.com/channel/" + partJson.channelId + "'>" +
|
| 424 |
+
"<img src='./img/metadata.png' style='margin-left:4px;width:20px;height:20px;;margin-right:5px;' alt='youtube metadata icon' >" +
|
| 425 |
+
"Inspect the metadata for the rest of this channel's videos" +
|
| 426 |
+
"</a></p>");
|
| 427 |
+
}
|
| 428 |
+
},
|
| 429 |
+
statistics: {
|
| 430 |
+
title: "Statistics",
|
| 431 |
+
postProcess: function (partJson, fullJson) {
|
| 432 |
+
const partDiv = $("#video-section #statistics");
|
| 433 |
+
|
| 434 |
+
if (partJson.hasOwnProperty("likeCount") && partJson.hasOwnProperty("dislikeCount")) {
|
| 435 |
+
const normalized = normalize(partJson.likeCount, partJson.dislikeCount);
|
| 436 |
+
|
| 437 |
+
const html =
|
| 438 |
+
"<p class='mb-15'>" +
|
| 439 |
+
"Normalized like ratio: " +
|
| 440 |
+
"<span style='color:green'>" + Math.trunc(normalized.a) + " like(s)</span> per " +
|
| 441 |
+
"<span style='color:red'>" + Math.trunc(normalized.b) + " dislike(s)</span>" +
|
| 442 |
+
"</p>";
|
| 443 |
+
partDiv.append(html);
|
| 444 |
+
} else if (!partJson.hasOwnProperty("likeCount")) {
|
| 445 |
+
partDiv.append("<p class='mb-15'>This video has <span class='orange'>likes disabled.</span></p>");
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
if (!partJson.hasOwnProperty("viewCount")) {
|
| 449 |
+
partDiv.append("<p class='mb-15'>This video has <span class='orange'>view counts disabled.</span></p>")
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
if (!partJson.hasOwnProperty("commentCount")) {
|
| 453 |
+
partDiv.append("<p class='mb-15'>This video has <span class='orange'>comments disabled.</span></p>")
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
if (!partJson.hasOwnProperty("dislikeCount")) {
|
| 457 |
+
partDiv.append(
|
| 458 |
+
"<p class='mb-15'>YouTube no longer provides the <span class='orange'>dislikeCount</span> since 2021-12-13 " +
|
| 459 |
+
"(<a href='https://developers.google.com/youtube/v3/revision_history#november-18,-2021' target='_blank'>see more here</a>). " +
|
| 460 |
+
"</p>");
|
| 461 |
+
partDiv.append("<p class='mb-15'>Want dislikes back? Check out the " +
|
| 462 |
+
"<a href='https://returnyoutubedislike.com/' target='_blank'>return-youtube-dislike</a> project!" +
|
| 463 |
+
"</p>");
|
| 464 |
+
// Potentially output RYD dislikes from their API.
|
| 465 |
+
// $.ajax({
|
| 466 |
+
// type: "GET",
|
| 467 |
+
// url: "https://returnyoutubedislikeapi.com/votes?videoId=" + fullJson.id
|
| 468 |
+
// }).then(function (res) {
|
| 469 |
+
// const dislikes = shared.idx(["dislikes"], res);
|
| 470 |
+
// if (dislikes) {
|
| 471 |
+
// partDiv.append("<p class='mb-15'>RYD Estimated Dislikes: <span class='orange'>" + dislikes + "</span></p>")
|
| 472 |
+
// }
|
| 473 |
+
// });
|
| 474 |
+
}
|
| 475 |
+
}
|
| 476 |
+
},
|
| 477 |
+
recordingDetails: {
|
| 478 |
+
title: "Geolocation",
|
| 479 |
+
postProcess: function (partJson, fullJson) {
|
| 480 |
+
const partDiv = $("#video-section #recordingDetails");
|
| 481 |
+
|
| 482 |
+
const location = partJson.location;
|
| 483 |
+
if (location && location.latitude && location.longitude) {
|
| 484 |
+
const latlng = location.latitude + "," + location.longitude;
|
| 485 |
+
const staticMap = "https://maps.googleapis.com/maps/api/staticmap?center=" + latlng + "&zoom=14&size=1000x300&key=AIzaSyAa-o55aIMt4YC0mhPyp8WfGql5DVg_fp4&markers=color:red|" + latlng;
|
| 486 |
+
|
| 487 |
+
const link = partJson.hasOwnProperty("locationDescription") ?
|
| 488 |
+
"https://maps.google.com/maps/search/" + encodeURI(partJson.locationDescription).replace(/'/g, "%27") + "/@" + latlng + ",14z" :
|
| 489 |
+
"https://maps.google.com/maps?q=loc:" + latlng;
|
| 490 |
+
|
| 491 |
+
const html =
|
| 492 |
+
"<p class='mb-15'><a href='" + link + "' target='_blank'>" +
|
| 493 |
+
"<img src='" + staticMap + "' alt='Google Maps Static Map'>" +
|
| 494 |
+
"<p>Click to open in Google Maps</p>" +
|
| 495 |
+
"</a></p>";
|
| 496 |
+
|
| 497 |
+
partDiv.append(html);
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
if (partJson.recordingDate && fullJson.snippet) {
|
| 501 |
+
const recordDate = moment(partJson.recordingDate).utc();
|
| 502 |
+
|
| 503 |
+
const dateHtml =
|
| 504 |
+
"<p class='mt-15 mb-15'>Recorded on " +
|
| 505 |
+
"<span class='orange'>" + recordDate.format("ddd, DD MMM YYYY") + "</span>" +
|
| 506 |
+
" (" + recordDate.fromNow() + "). YouTube Studio only allows creators to pick the date so there is no time on this timestamp." +
|
| 507 |
+
"</p>";
|
| 508 |
+
partDiv.append(dateHtml);
|
| 509 |
+
|
| 510 |
+
const published = moment(fullJson.snippet.publishedAt).utc();
|
| 511 |
+
const format = shared.formatDuration(getDuration(recordDate, published), false, true);
|
| 512 |
+
if (format === "0s") {
|
| 513 |
+
partDiv.append("<p class='mb-15'>The video was recorded <span class='orange'>same day</span> as the publish date.</p>")
|
| 514 |
+
} else if (published.isAfter(recordDate)) {
|
| 515 |
+
partDiv.append("<p class='mb-15'>The video was recorded <span class='orange'>" + format + "</span> before the publish date.</p>")
|
| 516 |
+
} else {
|
| 517 |
+
partDiv.append("<p class='mb-15'>The video was recorded <span class='orange'>" + format + "</span> after the publish date.</p>");
|
| 518 |
+
}
|
| 519 |
+
}
|
| 520 |
+
}
|
| 521 |
+
},
|
| 522 |
+
status: {
|
| 523 |
+
title: "Status",
|
| 524 |
+
postProcess: function (partJson) {
|
| 525 |
+
const partDiv = $("#video-section #status");
|
| 526 |
+
|
| 527 |
+
if (partJson.hasOwnProperty("privacyStatus")) {
|
| 528 |
+
if (partJson.privacyStatus !== "public") {
|
| 529 |
+
partDiv.append("<p class='mb-15'>This video has its privacy set to <span class='orange'>" + partJson.privacyStatus + "</span></p>")
|
| 530 |
+
}
|
| 531 |
+
}
|
| 532 |
+
if (partJson.hasOwnProperty("license")) {
|
| 533 |
+
if (partJson.license !== "youtube") {
|
| 534 |
+
partDiv.append("<p class='mb-15'>This video has its license set to <span class='orange'>" + partJson.license + "</span></p>")
|
| 535 |
+
}
|
| 536 |
+
}
|
| 537 |
+
if (partJson.hasOwnProperty("embeddable")) {
|
| 538 |
+
if (partJson.embeddable) {
|
| 539 |
+
partDiv.append("<p class='mb-15'>This video may be embedded on other websites</p>")
|
| 540 |
+
} else {
|
| 541 |
+
partDiv.append("<p class='mb-15'>This video may not be embedded on other websites</p>")
|
| 542 |
+
}
|
| 543 |
+
}
|
| 544 |
+
if (partJson.hasOwnProperty("madeForKids")) {
|
| 545 |
+
if (partJson.madeForKids) {
|
| 546 |
+
partDiv.append("<p class='mb-15'>This video is designated as <span class='orange'>child-directed</span></p>")
|
| 547 |
+
} else {
|
| 548 |
+
partDiv.append("<p class='mb-15'>This video is not child-directed</p>")
|
| 549 |
+
}
|
| 550 |
+
}
|
| 551 |
+
if (partJson.hasOwnProperty("selfDeclaredMadeForKids")) {
|
| 552 |
+
if (partJson.selfDeclaredMadeForKids) {
|
| 553 |
+
partDiv.append("<p class='mb-15'>The video owner designated this video as <span class='orange'>child-directed</span></p>")
|
| 554 |
+
} else {
|
| 555 |
+
partDiv.append("<p class='mb-15'>The video owner designated this video as not child-directed.</p>")
|
| 556 |
+
}
|
| 557 |
+
}
|
| 558 |
+
}
|
| 559 |
+
},
|
| 560 |
+
liveStreamingDetails: {
|
| 561 |
+
title: "Livestream Details",
|
| 562 |
+
postProcess: function (partJson) {
|
| 563 |
+
const partDiv = $("#video-section #liveStreamingDetails");
|
| 564 |
+
|
| 565 |
+
if (partJson.hasOwnProperty("actualStartTime")) {
|
| 566 |
+
const start = new Date(partJson.actualStartTime);
|
| 567 |
+
const dateHtml =
|
| 568 |
+
"<p class='mb-15'>The stream started on " +
|
| 569 |
+
"<span class='orange'>" + start.toUTCString() + "</span>" +
|
| 570 |
+
" (" + moment(start).utc().fromNow() + ") " + getConvertTime(start) +
|
| 571 |
+
"</p>";
|
| 572 |
+
partDiv.append(dateHtml);
|
| 573 |
+
}
|
| 574 |
+
if (partJson.hasOwnProperty("actualEndTime")) {
|
| 575 |
+
const end = new Date(partJson.actualEndTime);
|
| 576 |
+
const dateHtml =
|
| 577 |
+
"<p class='mb-15'>The stream ended on " +
|
| 578 |
+
"<span class='orange'>" + end.toUTCString() + "</span>" +
|
| 579 |
+
" (" + moment(end).utc().fromNow() + ") " + getConvertTime(end) +
|
| 580 |
+
"</p>";
|
| 581 |
+
partDiv.append(dateHtml);
|
| 582 |
+
}
|
| 583 |
+
|
| 584 |
+
const now = moment(new Date()).utc();
|
| 585 |
+
if (partJson.hasOwnProperty("scheduledStartTime") && partJson.hasOwnProperty("scheduledEndTime")) {
|
| 586 |
+
const start = moment(partJson.scheduledStartTime).utc();
|
| 587 |
+
const end = moment(partJson.scheduledEndTime).utc();
|
| 588 |
+
const format = shared.formatDuration(getDuration(start, end));
|
| 589 |
+
|
| 590 |
+
partDiv.append("<p class='mb-15'>The stream was scheduled to run for <span class='orange'>" + format + "</span></p>");
|
| 591 |
+
}
|
| 592 |
+
if (partJson.hasOwnProperty("scheduledStartTime") && !partJson.hasOwnProperty("actualStartTime")) {
|
| 593 |
+
// Stream hasn't started
|
| 594 |
+
const start = moment(partJson.scheduledStartTime).utc();
|
| 595 |
+
const format = shared.formatDuration(getDuration(start, now));
|
| 596 |
+
|
| 597 |
+
if (start.isAfter(now)) {
|
| 598 |
+
partDiv.append("<p class='mb-15'>The stream hasn't started yet. It will start in <span class='orange'>" + format + "</span></p>");
|
| 599 |
+
} else {
|
| 600 |
+
partDiv.append("<p class='mb-15'>The stream hasn't started yet. It was supposed to start <span class='orange'>" + format + "</span> ago</p>");
|
| 601 |
+
}
|
| 602 |
+
}
|
| 603 |
+
if (partJson.hasOwnProperty("actualStartTime") && partJson.hasOwnProperty("scheduledStartTime")) {
|
| 604 |
+
// Stream started. Time between schedule date and actual start?
|
| 605 |
+
const start = moment(partJson.actualStartTime).utc();
|
| 606 |
+
const scheduled = moment(partJson.scheduledStartTime).utc();
|
| 607 |
+
const format = shared.formatDuration(getDuration(start, scheduled));
|
| 608 |
+
if (start.isAfter(scheduled)) {
|
| 609 |
+
partDiv.append("<p class='mb-15'>The stream was <span class='orange'>" + format + "</span> late to start</p>")
|
| 610 |
+
} else {
|
| 611 |
+
partDiv.append("<p class='mb-15'>The stream was <span class='orange'>" + format + "</span> early to start</p>");
|
| 612 |
+
}
|
| 613 |
+
}
|
| 614 |
+
if (partJson.hasOwnProperty("actualStartTime") && !partJson.hasOwnProperty("actualEndTime")) {
|
| 615 |
+
// Stream started but still going. Time between start and now?
|
| 616 |
+
const start = moment(partJson.actualStartTime).utc();
|
| 617 |
+
const format = shared.formatDuration(getDuration(start, now));
|
| 618 |
+
|
| 619 |
+
partDiv.append("<p class='mb-15'>The stream is still going. It has been running for <span class='orange'>" + format + "</span></p>");
|
| 620 |
+
}
|
| 621 |
+
if (partJson.hasOwnProperty("actualStartTime") && partJson.hasOwnProperty("actualEndTime")) {
|
| 622 |
+
// Stream done. Time between start and end?
|
| 623 |
+
const start = moment(partJson.actualStartTime).utc();
|
| 624 |
+
const end = moment(partJson.actualEndTime).utc();
|
| 625 |
+
const format = shared.formatDuration(getDuration(start, end));
|
| 626 |
+
|
| 627 |
+
partDiv.append("<p class='mb-15'>The stream is over. It's length was <span class='orange'>" + format + "</span></p>");
|
| 628 |
+
}
|
| 629 |
+
}
|
| 630 |
+
},
|
| 631 |
+
localizations: {
|
| 632 |
+
title: "Localizations",
|
| 633 |
+
postProcess: function (partJson) {
|
| 634 |
+
const partDiv = $("#video-section #localizations");
|
| 635 |
+
|
| 636 |
+
processLocalizations(partDiv, partJson);
|
| 637 |
+
}
|
| 638 |
+
},
|
| 639 |
+
contentDetails: {
|
| 640 |
+
title: "Content Details",
|
| 641 |
+
postProcess: function (partJson) {
|
| 642 |
+
const partDiv = $("#video-section #contentDetails");
|
| 643 |
+
|
| 644 |
+
const duration = moment.duration(partJson.duration);
|
| 645 |
+
const format = shared.formatDuration(duration);
|
| 646 |
+
|
| 647 |
+
if (format === "0s") {
|
| 648 |
+
partDiv.append("<p class='mb-15'>A video can't be 0 seconds. This must be a livestream.</p>");
|
| 649 |
+
} else {
|
| 650 |
+
partDiv.append("<p class='mb-15'>The video length was <span style='color:orange'>" + format + "</span></p>");
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
if (partJson.hasOwnProperty('regionRestriction')) {
|
| 654 |
+
const restriction = partJson.regionRestriction;
|
| 655 |
+
|
| 656 |
+
const totalIsoCodes = iso3166.codes.length;
|
| 657 |
+
// Should have only one or the other, never both
|
| 658 |
+
let message;
|
| 659 |
+
if (restriction.hasOwnProperty('allowed')) {
|
| 660 |
+
partDiv.append("<p class='mb-15'>This video is <span class='orange'>region-restriction</span> <span class='green'>allowed</span>.");
|
| 661 |
+
message = "These <span class='orange'>" + restriction.allowed.length + " / " + totalIsoCodes + "</span> region(s) are <span class='green'>allowed</span> to watch the video.</p>";
|
| 662 |
+
restriction.allowed.sort();
|
| 663 |
+
} else if (restriction.hasOwnProperty('blocked')) {
|
| 664 |
+
partDiv.append("<p class='mb-15'>This video is <span class='orange'>region-restriction</span> <span class='red'>blocked</span>.");
|
| 665 |
+
message = "These <span class='orange'>" + restriction.blocked.length + " / " + totalIsoCodes + "</span> region(s) are <span class='red'>not allowed</span> to watch the video.</p>";
|
| 666 |
+
restriction.blocked.sort();
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
const inList = restriction.allowed || restriction.blocked;
|
| 670 |
+
const translations = [];
|
| 671 |
+
inList.forEach(function (code) {
|
| 672 |
+
const result = iso3166.lookup(code);
|
| 673 |
+
const name = (result ? result.name : 'ISO-3166 Could not translate')
|
| 674 |
+
|
| 675 |
+
translations.push("<li><span class='orange'>" + String(code).toUpperCase() + "</span> which is <span class='orange'>" + name + "</span></li>")
|
| 676 |
+
});
|
| 677 |
+
partDiv.append(
|
| 678 |
+
"<p class='mb-15'><a data-bs-toggle='collapse' href='#restriction-list-1'>" + message + "</a></p>" +
|
| 679 |
+
"<div id='restriction-list-1' class='collapse'>" +
|
| 680 |
+
"<ul>" + translations.join("") + "</ul>" +
|
| 681 |
+
"</div>");
|
| 682 |
+
|
| 683 |
+
const notInList = [];
|
| 684 |
+
iso3166.codes.forEach(function (code) {
|
| 685 |
+
if (inList.indexOf(code.alpha2) === -1) {
|
| 686 |
+
notInList.push(code.alpha2);
|
| 687 |
+
}
|
| 688 |
+
});
|
| 689 |
+
let message2;
|
| 690 |
+
if (restriction.hasOwnProperty('allowed')) {
|
| 691 |
+
message2 = "These <span class='orange'>" + notInList.length + " / " + totalIsoCodes + "</span> region(s) are <span class='red'>not allowed</span> to watch the video.";
|
| 692 |
+
restriction.allowed.sort();
|
| 693 |
+
} else if (restriction.hasOwnProperty('blocked')) {
|
| 694 |
+
message2 = "These <span class='orange'>" + notInList.length + " / " + totalIsoCodes + "</span> region(s) are <span class='green'>allowed</span> to watch the video.";
|
| 695 |
+
restriction.blocked.sort();
|
| 696 |
+
}
|
| 697 |
+
notInList.sort();
|
| 698 |
+
const translations2 = [];
|
| 699 |
+
notInList.forEach(function (code) {
|
| 700 |
+
const result = iso3166.lookup(code);
|
| 701 |
+
const name = (result ? result.name : 'ISO-3166 Could not translate')
|
| 702 |
+
|
| 703 |
+
translations2.push("<li><span class='orange'>" + String(code).toUpperCase() + "</span> which is <span class='orange'>" + name + "</span></li>");
|
| 704 |
+
});
|
| 705 |
+
partDiv.append(
|
| 706 |
+
"<p class='mb-15'><a data-bs-toggle='collapse' href='#restriction-list-2'>" + message2 + "</a></p>" +
|
| 707 |
+
"<div id='restriction-list-2' class='collapse'>" +
|
| 708 |
+
"<ul>" + translations2.join("") + "</ul>" +
|
| 709 |
+
"</div>");
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
+
const contentRating = partJson.contentRating;
|
| 713 |
+
if (!$.isEmptyObject(contentRating)) {
|
| 714 |
+
const pairs = [];
|
| 715 |
+
|
| 716 |
+
Object.keys(contentRating).forEach(function (key) {
|
| 717 |
+
pairs.push(key + "/" + contentRating[key]);
|
| 718 |
+
});
|
| 719 |
+
|
| 720 |
+
partDiv.append("<p class='mb-15'>This video has a content rating of <span class='orange'>" + pairs.join(", ") + "</span></p>")
|
| 721 |
+
}
|
| 722 |
+
}
|
| 723 |
+
},
|
| 724 |
+
topicDetails: {
|
| 725 |
+
title: "Topic Details",
|
| 726 |
+
postProcess: function (partJson) {
|
| 727 |
+
const partDiv = $("#video-section #topicDetails");
|
| 728 |
+
|
| 729 |
+
const topics = [];
|
| 730 |
+
(partJson.topicCategories || []).forEach(function (categoryUrl) {
|
| 731 |
+
const text = categoryUrl.substr(categoryUrl.lastIndexOf('/') + 1).replace(/_/g, " ");
|
| 732 |
+
|
| 733 |
+
topics.push("<li><a target='_blank' href='" + categoryUrl + "'>" + text + "</a></li>");
|
| 734 |
+
});
|
| 735 |
+
|
| 736 |
+
partDiv.append("<p class='mb-15'><ul>" + topics.join("") + "</ul></p>");
|
| 737 |
+
}
|
| 738 |
+
}
|
| 739 |
+
},
|
| 740 |
+
|
| 741 |
+
/**
|
| 742 |
+
* Can't access part(s): auditDetails, contentOwnerDetails
|
| 743 |
+
* Useless part(s): id
|
| 744 |
+
* Every other part below:
|
| 745 |
+
*/
|
| 746 |
+
channel: {
|
| 747 |
+
snippet: {
|
| 748 |
+
title: "Snippet",
|
| 749 |
+
postProcess: function (partJson, fullJson) {
|
| 750 |
+
const partDiv = $("#channel-section #snippet");
|
| 751 |
+
|
| 752 |
+
const thumbs = partJson.thumbnails;
|
| 753 |
+
const thumbUrl = (thumbs.maxres || thumbs.high || thumbs.medium || thumbs.default || {url: "https://placehold.it/240x240"}).url;
|
| 754 |
+
|
| 755 |
+
partDiv.append("<a target='_blank' href='https://www.youtube.com/channel/" + fullJson.id + "'><img id='channel-thumb' src='" + thumbUrl + "' class='mb-15 profile'></a>");
|
| 756 |
+
partDiv.append("<p class='mb-15' style='font-size: 1.25em'>" + partJson.title + "</p>");
|
| 757 |
+
|
| 758 |
+
const published = new Date(partJson.publishedAt);
|
| 759 |
+
const dateHtml =
|
| 760 |
+
"<p class='mb-15'>Channel created on " +
|
| 761 |
+
"<span class='orange'>" + published.toUTCString() + "</span>" +
|
| 762 |
+
" (" + moment(published).utc().fromNow() + ")" + getConvertTime(published) +
|
| 763 |
+
"</p>";
|
| 764 |
+
partDiv.append(dateHtml);
|
| 765 |
+
|
| 766 |
+
if (partJson.hasOwnProperty("country")) {
|
| 767 |
+
const countryCode = partJson.country;
|
| 768 |
+
const country = bcp47.lookup(countryCode).country;
|
| 769 |
+
const translated = country ? " which is <span class='orange'>" + country.name + "</span>" : "";
|
| 770 |
+
partDiv.append("<p class='mb-15'>The channel is associated with country code <span class='orange'>" + countryCode + "</span>" + translated + "</p>");
|
| 771 |
+
} else {
|
| 772 |
+
partDiv.append("<p class='mb-15'>The channel doesn't have an associated country.</p>");
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
if (partJson.hasOwnProperty("customUrl")) {
|
| 776 |
+
const urlPart = partJson.customUrl.startsWith('@') ? '' : 'c/';
|
| 777 |
+
const customUrl = "https://www.youtube.com/" + urlPart + partJson.customUrl;
|
| 778 |
+
|
| 779 |
+
partDiv.append("<p class='mb-15'>The channel has a custom url of value '<a target='_blank' href='" + customUrl + "'>" + partJson.customUrl + "</a>'</p>");
|
| 780 |
+
}
|
| 781 |
+
|
| 782 |
+
partDiv.append("<p class='mb-15'>The channel id is <span class='orange'>" + fullJson.id + "</span></p>");
|
| 783 |
+
}
|
| 784 |
+
},
|
| 785 |
+
statistics: {
|
| 786 |
+
title: "Statistics",
|
| 787 |
+
postProcess: function (partJson, fullJson) {
|
| 788 |
+
const partDiv = $("#channel-section #statistics");
|
| 789 |
+
|
| 790 |
+
const subLevels = {
|
| 791 |
+
graphite: {
|
| 792 |
+
min: 1,
|
| 793 |
+
max: 999,
|
| 794 |
+
qualCount: "1-1k",
|
| 795 |
+
learnMore: "https://www.youtube.com/intl/en-GB/creators/benefits/graphite/"
|
| 796 |
+
},
|
| 797 |
+
opal: {
|
| 798 |
+
min: 1000,
|
| 799 |
+
max: 9999,
|
| 800 |
+
qualCount: "1k-10k",
|
| 801 |
+
learnMore: "https://www.youtube.com/intl/en-GB/creators/benefits/opal/"
|
| 802 |
+
},
|
| 803 |
+
bronze: {
|
| 804 |
+
min: 10000,
|
| 805 |
+
max: 99999,
|
| 806 |
+
qualCount: "10k-100k",
|
| 807 |
+
learnMore: "https://www.youtube.com/intl/en-GB/creators/benefits/bronze/"
|
| 808 |
+
},
|
| 809 |
+
silver: {
|
| 810 |
+
min: 100000,
|
| 811 |
+
max: 999999,
|
| 812 |
+
qualCount: "100k-1m",
|
| 813 |
+
learnMore: "https://www.youtube.com/intl/en-GB/creators/benefits/silver/"
|
| 814 |
+
},
|
| 815 |
+
gold: {
|
| 816 |
+
min: 1000000,
|
| 817 |
+
max: 9999999,
|
| 818 |
+
qualCount: "1m-10m",
|
| 819 |
+
learnMore: "https://www.youtube.com/intl/en-GB/creators/benefits/silver/"
|
| 820 |
+
},
|
| 821 |
+
diamond: {
|
| 822 |
+
min: 10000000,
|
| 823 |
+
max: Number.MAX_SAFE_INTEGER,
|
| 824 |
+
qualCount: "10m+",
|
| 825 |
+
learnMore: "https://www.youtube.com/intl/en-GB/creators/benefits/silver/"
|
| 826 |
+
}
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
const subs = partJson.subscriberCount;
|
| 830 |
+
const learnMore = "Click <a target='_blank' href='https://www.youtube.com/intl/en-GB/creators/benefits/'>here</a> to learn more.";
|
| 831 |
+
|
| 832 |
+
for (let levelName in subLevels) {
|
| 833 |
+
const level = subLevels[levelName];
|
| 834 |
+
if (subs >= level.min && subs <= level.max) {
|
| 835 |
+
partDiv.append("<p class='mb-15'>This channel's subscriber count qualifies for benefit level <span class='orange'>" + levelName + " </span> (" + level.qualCount + "). " + learnMore + "</p>")
|
| 836 |
+
}
|
| 837 |
+
}
|
| 838 |
+
|
| 839 |
+
if (partJson.hiddenSubscriberCount) {
|
| 840 |
+
partDiv.append("<p class='mb-15'>This channel has their subscriber count <span class='orange'>hidden</span>.</p>");
|
| 841 |
+
} else if (subs <= 0) {
|
| 842 |
+
partDiv.append("<p class='mb-15'>This channel has no subscribers and does not qualify for any benefit level. " + learnMore + "</p>");
|
| 843 |
+
} else {
|
| 844 |
+
partDiv.append("<p class='mb-15'>Check out this channel on <a target='_blank' href='https://socialblade.com/youtube/channel/" + fullJson.id + "'>SocialBlade</a>.</p>");
|
| 845 |
+
}
|
| 846 |
+
|
| 847 |
+
if (partJson.videoCount > 0) {
|
| 848 |
+
partDiv.append("<p class='mb-15'><a style='display:inline;vertical-align:middle' target='_blank' href='./bulk?submit=true&url=https://www.youtube.com/channel/" + fullJson.id + "'>" +
|
| 849 |
+
"<img src='./img/metadata.png' style='margin-left:4px;width:20px;height:20px;;margin-right:5px;' alt='youtube metadata icon' >" +
|
| 850 |
+
"Inspect the metadata for all of this channel's videos" +
|
| 851 |
+
"</a></p>");
|
| 852 |
+
} else {
|
| 853 |
+
partDiv.append("<p class='mb-15'>This channel has no public videos.</p>");
|
| 854 |
+
}
|
| 855 |
+
}
|
| 856 |
+
},
|
| 857 |
+
brandingSettings: {
|
| 858 |
+
title: "Branding Settings",
|
| 859 |
+
postProcess: function (partJson) {
|
| 860 |
+
const partDiv = $("#channel-section #brandingSettings");
|
| 861 |
+
|
| 862 |
+
const bannerImage = shared.idx(["image", "bannerExternalUrl"], partJson);
|
| 863 |
+
if (bannerImage) {
|
| 864 |
+
partDiv.append("<img id='channel-banner' src='" + bannerImage + "' class='mb-15'>");
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
if (partJson.channel.hasOwnProperty("trackingAnalyticsAccountId")) {
|
| 868 |
+
partDiv.append("<p class='mb-15'>This channel is tracking and measuring traffic with Google Analytics <span class='orange'>" + partJson.channel.trackingAnalyticsAccountId + "</span></p>")
|
| 869 |
+
}
|
| 870 |
+
|
| 871 |
+
if (partJson.channel.hasOwnProperty("moderateComments")) {
|
| 872 |
+
if (partJson.channel.moderateComments) {
|
| 873 |
+
partDiv.append("<p class='mb-15'>Comments on the channel page are <span class='orange'>moderated</span> and require approval by the owner.</p>")
|
| 874 |
+
} else {
|
| 875 |
+
partDiv.append("<p class='mb-15'>Comments on the channel page are not moderated.</p>")
|
| 876 |
+
}
|
| 877 |
+
}
|
| 878 |
+
|
| 879 |
+
if (partJson.channel.keywords) {
|
| 880 |
+
const keywords = partJson.channel.keywords;
|
| 881 |
+
const parsed = [];
|
| 882 |
+
|
| 883 |
+
// Custom parser because regex for all languages is funky
|
| 884 |
+
// and why doesn't browser JS regex support \p{L} !?!?!
|
| 885 |
+
// Also, why didn't google make this an array like video tags?
|
| 886 |
+
let word = "";
|
| 887 |
+
let inQuotes = false;
|
| 888 |
+
for (let i = 0; i < keywords.length; i++) {
|
| 889 |
+
const char = keywords.charAt(i);
|
| 890 |
+
|
| 891 |
+
if (char === '"' && inQuotes === false) {
|
| 892 |
+
inQuotes = true;
|
| 893 |
+
} else if (char === '"' && inQuotes === true) {
|
| 894 |
+
inQuotes = false;
|
| 895 |
+
}
|
| 896 |
+
|
| 897 |
+
if (char !== '"') {
|
| 898 |
+
if (char === " " && inQuotes === false) {
|
| 899 |
+
parsed.push(word);
|
| 900 |
+
word = "";
|
| 901 |
+
} else if (char !== " " || inQuotes === true) {
|
| 902 |
+
word += char;
|
| 903 |
+
}
|
| 904 |
+
}
|
| 905 |
+
}
|
| 906 |
+
if (parsed.indexOf(word) === -1) {
|
| 907 |
+
parsed.push(word);
|
| 908 |
+
}
|
| 909 |
+
|
| 910 |
+
const keywordsHtml =
|
| 911 |
+
"<p class='mb-15'>Channel Keyword(s): " +
|
| 912 |
+
(parsed && parsed.length ?
|
| 913 |
+
"<span class='tag'>" +
|
| 914 |
+
parsed.join("</span><span class='comma'>, </span><span class='tag'>") +
|
| 915 |
+
"</span>" : "") +
|
| 916 |
+
"</p>";
|
| 917 |
+
partDiv.append(keywordsHtml);
|
| 918 |
+
} else {
|
| 919 |
+
partDiv.append("<p class='mb-15'>There were no keywords.</p>")
|
| 920 |
+
}
|
| 921 |
+
}
|
| 922 |
+
},
|
| 923 |
+
contentDetails: {
|
| 924 |
+
title: "Content Details",
|
| 925 |
+
postProcess: function (partJson) {
|
| 926 |
+
const partDiv = $("#channel-section #contentDetails");
|
| 927 |
+
|
| 928 |
+
const related = partJson.relatedPlaylists;
|
| 929 |
+
if (related) {
|
| 930 |
+
if (related.hasOwnProperty("uploads") && related.uploads) {
|
| 931 |
+
partDiv.append("<p class='mb-15'><a target='_blank' href='https://www.youtube.com/playlist?list=" + related.uploads + "'>Uploads playlist</a></p>")
|
| 932 |
+
}
|
| 933 |
+
if (related.hasOwnProperty("favorites") && related.favorites) {
|
| 934 |
+
partDiv.append("<p class='mb-15'><a target='_blank' href='https://www.youtube.com/playlist?list=" + related.favorites + "'>Favorites playlist</a></p>")
|
| 935 |
+
}
|
| 936 |
+
if (related.hasOwnProperty("likes") && related.likes) {
|
| 937 |
+
partDiv.append("<p class='mb-15'><a target='_blank' href='https://www.youtube.com/playlist?list=" + related.likes + "'>Likes playlist</a></p>")
|
| 938 |
+
}
|
| 939 |
+
}
|
| 940 |
+
}
|
| 941 |
+
},
|
| 942 |
+
localizations: {
|
| 943 |
+
title: "Localizations",
|
| 944 |
+
postProcess: function (partJson) {
|
| 945 |
+
const partDiv = $("#channel-section #localizations");
|
| 946 |
+
|
| 947 |
+
processLocalizations(partDiv, partJson);
|
| 948 |
+
}
|
| 949 |
+
},
|
| 950 |
+
status: {
|
| 951 |
+
title: "Status",
|
| 952 |
+
postProcess: function (partJson) {
|
| 953 |
+
const partDiv = $("#channel-section #status");
|
| 954 |
+
|
| 955 |
+
if (partJson.hasOwnProperty("madeForKids")) {
|
| 956 |
+
if (partJson.madeForKids) {
|
| 957 |
+
partDiv.append("<p class='mb-15'>This channel is designated as <span class='orange'>child-directed</span></p>")
|
| 958 |
+
} else {
|
| 959 |
+
partDiv.append("<p class='mb-15'>This channel is not child-directed</p>")
|
| 960 |
+
}
|
| 961 |
+
}
|
| 962 |
+
if (partJson.hasOwnProperty("selfDeclaredMadeForKids")) {
|
| 963 |
+
if (partJson.selfDeclaredMadeForKids) {
|
| 964 |
+
partDiv.append("<p class='mb-15'>The channel owner designated this channel as <span class='orange'>child-directed</span></p>")
|
| 965 |
+
} else {
|
| 966 |
+
partDiv.append("<p class='mb-15'>The channel owner designated this channel as not child-directed.</p>")
|
| 967 |
+
}
|
| 968 |
+
}
|
| 969 |
+
}
|
| 970 |
+
},
|
| 971 |
+
topicDetails: {
|
| 972 |
+
title: "Topic Details",
|
| 973 |
+
postProcess: function (partJson) {
|
| 974 |
+
const partDiv = $("#channel-section #topicDetails");
|
| 975 |
+
|
| 976 |
+
const topics = [];
|
| 977 |
+
(partJson.topicCategories || []).forEach(function (categoryUrl) {
|
| 978 |
+
const text = categoryUrl.substr(categoryUrl.lastIndexOf('/') + 1).replace(/_/g, " ");
|
| 979 |
+
|
| 980 |
+
topics.push("<li><a target='_blank' href='" + categoryUrl + "'>" + text + "</a></li>");
|
| 981 |
+
});
|
| 982 |
+
|
| 983 |
+
partDiv.append("<p class='mb-15'><ul>" + topics.join("") + "</ul></p>");
|
| 984 |
+
}
|
| 985 |
+
}
|
| 986 |
+
},
|
| 987 |
+
|
| 988 |
+
/**
|
| 989 |
+
* Useless part(s): id, player
|
| 990 |
+
* Every other part below:
|
| 991 |
+
*/
|
| 992 |
+
playlist: {
|
| 993 |
+
snippet: {
|
| 994 |
+
title: "Snippet",
|
| 995 |
+
postProcess: function (partJson, fullJson) {
|
| 996 |
+
const partDiv = $("#playlist-section #snippet");
|
| 997 |
+
|
| 998 |
+
const thumbs = partJson.thumbnails;
|
| 999 |
+
const thumbUrl = (thumbs.maxres || thumbs.high || thumbs.medium || thumbs.default || {url: "https://placehold.it/480x360"}).url;
|
| 1000 |
+
|
| 1001 |
+
partDiv.append("<a target='_blank' href='https://www.youtube.com/playlist?list=" + fullJson.id + "'><img id='playlist-thumb' src='" + thumbUrl + "' class='mb-15'></a>");
|
| 1002 |
+
partDiv.append("<p class='mb-15' style='font-size: 1.25em'>" + partJson.title + "</p>");
|
| 1003 |
+
|
| 1004 |
+
const authorHtml =
|
| 1005 |
+
"<p class='mb-15'>Published by " +
|
| 1006 |
+
"<a href='https://www.youtube.com/channel/" + partJson.channelId + "' target='_blank'>" +
|
| 1007 |
+
partJson.channelTitle +
|
| 1008 |
+
"</a>" +
|
| 1009 |
+
"</p>";
|
| 1010 |
+
partDiv.append(authorHtml);
|
| 1011 |
+
|
| 1012 |
+
const published = new Date(partJson.publishedAt);
|
| 1013 |
+
const dateHtml =
|
| 1014 |
+
"<p class='mb-15'>Playlist created on " +
|
| 1015 |
+
"<span class='orange'>" + published.toUTCString() + "</span>" +
|
| 1016 |
+
" (" + moment(published).utc().fromNow() + ")" + getConvertTime(published) +
|
| 1017 |
+
"</p>";
|
| 1018 |
+
partDiv.append(dateHtml);
|
| 1019 |
+
|
| 1020 |
+
partDiv.append("<p class='mb-15'>The playlist id is <span class='orange'>" + fullJson.id + "</span></p>");
|
| 1021 |
+
|
| 1022 |
+
partDiv.append("<p class='mb-15'><a style='display:inline;vertical-align:middle' target='_blank' href='./bulk?submit=true&url=https://www.youtube.com/channel/" + fullJson.id + "'>" +
|
| 1023 |
+
"<img src='./img/metadata.png' style='margin-left:4px;width:20px;height:20px;margin-right:5px;' alt='youtube metadata icon' >" +
|
| 1024 |
+
"Inspect the metadata for all of this playlist's videos" +
|
| 1025 |
+
"</a></p>");
|
| 1026 |
+
}
|
| 1027 |
+
},
|
| 1028 |
+
status: {
|
| 1029 |
+
title: "Status",
|
| 1030 |
+
postProcess: function (partJson) {
|
| 1031 |
+
const partDiv = $("#playlist-section #status");
|
| 1032 |
+
}
|
| 1033 |
+
},
|
| 1034 |
+
localizations: {
|
| 1035 |
+
title: "Localizations",
|
| 1036 |
+
postProcess: function (partJson) {
|
| 1037 |
+
const partDiv = $("#playlist-section #localizations");
|
| 1038 |
+
|
| 1039 |
+
processLocalizations(partDiv, partJson);
|
| 1040 |
+
}
|
| 1041 |
+
},
|
| 1042 |
+
contentDetails: {
|
| 1043 |
+
title: "Content Details",
|
| 1044 |
+
postProcess: function (partJson) {
|
| 1045 |
+
const partDiv = $("#playlist-section #contentDetails");
|
| 1046 |
+
}
|
| 1047 |
+
}
|
| 1048 |
+
}
|
| 1049 |
+
};
|
| 1050 |
+
|
| 1051 |
+
function errorState(message, funcAppend, errorJson) {
|
| 1052 |
+
$("#video,#playlist,#channel").hide();
|
| 1053 |
+
|
| 1054 |
+
let reasonAppend;
|
| 1055 |
+
const reason = shared.idx(["responseJSON", "error", "errors", 0, "reason"], errorJson);
|
| 1056 |
+
if (reason === "quotaExceeded") {
|
| 1057 |
+
$("#quota").show();
|
| 1058 |
+
reasonAppend = $("#quota-reason-append");
|
| 1059 |
+
reasonAppend.empty();
|
| 1060 |
+
} else {
|
| 1061 |
+
$("#unknown").show();
|
| 1062 |
+
$("#reason").html(message);
|
| 1063 |
+
|
| 1064 |
+
reasonAppend = $("#reason-append");
|
| 1065 |
+
reasonAppend.empty();
|
| 1066 |
+
|
| 1067 |
+
if (funcAppend) {
|
| 1068 |
+
funcAppend(reasonAppend);
|
| 1069 |
+
}
|
| 1070 |
+
}
|
| 1071 |
+
if (errorJson) {
|
| 1072 |
+
reasonAppend.append("<pre><code class='prettyprint language-json'></code></pre>");
|
| 1073 |
+
|
| 1074 |
+
const json = reasonAppend.find("code");
|
| 1075 |
+
json.text(JSON.stringify(errorJson, null, 4));
|
| 1076 |
+
hljs.highlightElement(json[0]);
|
| 1077 |
+
}
|
| 1078 |
+
}
|
| 1079 |
+
|
| 1080 |
+
function attemptLoadFilmot(parsedInput) {
|
| 1081 |
+
$("#filmot").hide();
|
| 1082 |
+
|
| 1083 |
+
if (parsedInput.type === "video_id") {
|
| 1084 |
+
// Note: Filmot has limited resources. Do not misuse, please contact about usage first.
|
| 1085 |
+
// https://filmot.com/contactus
|
| 1086 |
+
const hostname = window.location.hostname;
|
| 1087 |
+
if (hostname !== "localhost" && hostname !== "mattw.io") {
|
| 1088 |
+
console.log("do not call filmot from other instances")
|
| 1089 |
+
return;
|
| 1090 |
+
}
|
| 1091 |
+
if (!shared.isValidVideoId(parsedInput.value)) {
|
| 1092 |
+
console.log("do not call filmot for invalid ids")
|
| 1093 |
+
$("#reason-append").append("<p class='mb-15'>However, this is an <span class='orange'>invalid</span> video id and must follow pattern: <span class='orange'>[A-Za-z0-9_-]{10}[AEIMQUYcgkosw048]</span>.</p>");
|
| 1094 |
+
return;
|
| 1095 |
+
}
|
| 1096 |
+
|
| 1097 |
+
$.ajax({
|
| 1098 |
+
cache: false,
|
| 1099 |
+
data: {
|
| 1100 |
+
key: "md5paNgdbaeudounjp39",
|
| 1101 |
+
id: parsedInput.value,
|
| 1102 |
+
flags: 1 // Get channel and description too,
|
| 1103 |
+
},
|
| 1104 |
+
dataType: "json",
|
| 1105 |
+
type: "GET",
|
| 1106 |
+
timeout: 5000,
|
| 1107 |
+
url: "https://filmot.com/api/getvideos",
|
| 1108 |
+
}).done(function (res) {
|
| 1109 |
+
const filmotAppend = $("#filmot-append");
|
| 1110 |
+
filmotAppend.empty();
|
| 1111 |
+
|
| 1112 |
+
const video = shared.idx([0], res);
|
| 1113 |
+
if (!video) {
|
| 1114 |
+
filmotAppend.append("<p class='mb-15'>No archive about this video id.</p>");
|
| 1115 |
+
$("#filmot").show();
|
| 1116 |
+
return;
|
| 1117 |
+
}
|
| 1118 |
+
|
| 1119 |
+
exportData["filmot"] = video;
|
| 1120 |
+
|
| 1121 |
+
filmotAppend.append("<pre><code class='prettyprint language-json'></code></pre>");
|
| 1122 |
+
const json = filmotAppend.find("code");
|
| 1123 |
+
json.text(JSON.stringify(video, null, 4));
|
| 1124 |
+
hljs.highlightElement(json[0]);
|
| 1125 |
+
|
| 1126 |
+
$("#filmot").show();
|
| 1127 |
+
|
| 1128 |
+
const titleHtml = "<p class='mb-15' style='font-size: 1.25em'>" + video.title + "</p>";
|
| 1129 |
+
filmotAppend.append(titleHtml);
|
| 1130 |
+
|
| 1131 |
+
const authorHtml =
|
| 1132 |
+
"<p class='mb-15'>Published by " +
|
| 1133 |
+
"<a href='https://www.youtube.com/channel/" + video.channelid + "' target='_blank'>" +
|
| 1134 |
+
video.channelname +
|
| 1135 |
+
"</a>" +
|
| 1136 |
+
"</p>";
|
| 1137 |
+
filmotAppend.append(authorHtml);
|
| 1138 |
+
|
| 1139 |
+
const published = new Date(video.uploaddate);
|
| 1140 |
+
const dateHtml =
|
| 1141 |
+
"<p class='mb-15'>Published on " +
|
| 1142 |
+
"<span class='orange'>" + moment(published).format("ddd, DD MMM YYYY") + "</span>" +
|
| 1143 |
+
" (" + moment(published).utc().fromNow() + ")" +
|
| 1144 |
+
"</p>";
|
| 1145 |
+
filmotAppend.append(dateHtml);
|
| 1146 |
+
|
| 1147 |
+
const duration = moment.duration({"seconds": video.duration});
|
| 1148 |
+
const format = shared.formatDuration(duration);
|
| 1149 |
+
if (format === "0s") {
|
| 1150 |
+
filmotAppend.append("<p class='mb-15'>A video can't be 0 seconds. This must be a livestream.</p>");
|
| 1151 |
+
} else {
|
| 1152 |
+
filmotAppend.append("<p class='mb-15'>The video length was <span style='color:orange'>" + format + "</span></p>");
|
| 1153 |
+
}
|
| 1154 |
+
|
| 1155 |
+
filmotAppend.append(getSuggestedHtml(null, null, null, video));
|
| 1156 |
+
}).fail(function (err) {
|
| 1157 |
+
console.warn(err);
|
| 1158 |
+
})
|
| 1159 |
+
} else if (parsedInput.type === "channel_id") {
|
| 1160 |
+
if (!shared.isValidChannelId(parsedInput.value)) {
|
| 1161 |
+
$("#reason-append").append("<p class='mb-15'>However, this is an <span class='orange'>invalid</span> channel id and must follow pattern: <span class='orange'>[A-Za-z0-9_-]{21}[AQgw]</span>.</p>");
|
| 1162 |
+
}
|
| 1163 |
+
}
|
| 1164 |
+
}
|
| 1165 |
+
|
| 1166 |
+
function attemptWaybackCDX(parsedInput) {
|
| 1167 |
+
if (parsedInput.type === "video_id") {
|
| 1168 |
+
$("#wayback").show();
|
| 1169 |
+
$("#wayback-show-older,#wayback-copy").hide();
|
| 1170 |
+
$("#wayback-append").html("Checking... <span id='wayback-progress'></span>")
|
| 1171 |
+
|
| 1172 |
+
const results = []
|
| 1173 |
+
const promises = []
|
| 1174 |
+
const cdxUrls = []
|
| 1175 |
+
|
| 1176 |
+
// Video thumbs
|
| 1177 |
+
cdxUrls.push("https://web.archive.org/cdx/search/cdx?url=i.ytimg.com/vi/" + parsedInput.value + "*&collapse=digest&filter=statuscode:200&mimetype:image/jpeg&output=json")
|
| 1178 |
+
cdxUrls.push("https://web.archive.org/cdx/search/cdx?url=s.ytimg.com/vi/" + parsedInput.value + "*&collapse=digest&filter=statuscode:200&mimetype:image/jpeg&output=json")
|
| 1179 |
+
cdxUrls.push("https://web.archive.org/cdx/search/cdx?url=img.youtube.com/vi/" + parsedInput.value + "*&collapse=digest&filter=statuscode:200&mimetype:image/jpeg&output=json")
|
| 1180 |
+
|
| 1181 |
+
// Storyboard thumbs
|
| 1182 |
+
const sbSub = ["i", "i9", "i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8"]
|
| 1183 |
+
for (let i in sbSub) {
|
| 1184 |
+
const subdomain = sbSub[i];
|
| 1185 |
+
const cdxUrl = "https://web.archive.org/cdx/search/cdx?url=" + subdomain + ".ytimg.com/sb/" + parsedInput.value + "*&collapse=digest&filter=statuscode:200&mimetype:image/jpeg&output=json"
|
| 1186 |
+
|
| 1187 |
+
cdxUrls.push(cdxUrl)
|
| 1188 |
+
}
|
| 1189 |
+
|
| 1190 |
+
let progress = 0
|
| 1191 |
+
let failed = 0
|
| 1192 |
+
$("#wayback-progress").html(`${progress+failed}/${cdxUrls.length} done; ${failed} failed`)
|
| 1193 |
+
|
| 1194 |
+
promises.push(new Promise(function (resolve) {
|
| 1195 |
+
function cdxCall(i) {
|
| 1196 |
+
if (i >= cdxUrls.length) {
|
| 1197 |
+
console.log("promise done")
|
| 1198 |
+
resolve()
|
| 1199 |
+
return
|
| 1200 |
+
}
|
| 1201 |
+
console.log("calling " + i)
|
| 1202 |
+
|
| 1203 |
+
const url = cdxUrls[i]
|
| 1204 |
+
if (!url) {
|
| 1205 |
+
resolve()
|
| 1206 |
+
return
|
| 1207 |
+
}
|
| 1208 |
+
|
| 1209 |
+
const promise = new Promise(function (resolve2) {
|
| 1210 |
+
$.ajax({
|
| 1211 |
+
url: "https://cors-proxy-mw324.herokuapp.com/" + url,
|
| 1212 |
+
}).done(function (res) {
|
| 1213 |
+
console.log(url)
|
| 1214 |
+
if (res) {
|
| 1215 |
+
for (let i = 0; i < res.length; i++) {
|
| 1216 |
+
results.push(res[i])
|
| 1217 |
+
}
|
| 1218 |
+
}
|
| 1219 |
+
progress += 1
|
| 1220 |
+
$("#wayback-progress").html(`${progress+failed}/${cdxUrls.length} done; ${failed} failed`)
|
| 1221 |
+
resolve2()
|
| 1222 |
+
}).fail(function (err) {
|
| 1223 |
+
console.error(url)
|
| 1224 |
+
failed += 1
|
| 1225 |
+
$("#wayback-progress").html(`${progress+failed}/${cdxUrls.length} done; ${failed} failed`)
|
| 1226 |
+
resolve2()
|
| 1227 |
+
})
|
| 1228 |
+
})
|
| 1229 |
+
|
| 1230 |
+
promises.push(promise)
|
| 1231 |
+
promise.then(function () {cdxCall(i + 1)})
|
| 1232 |
+
}
|
| 1233 |
+
cdxCall(0)
|
| 1234 |
+
}))
|
| 1235 |
+
|
| 1236 |
+
Promise.all(promises).then(function () {
|
| 1237 |
+
console.log("Done!")
|
| 1238 |
+
console.log(results)
|
| 1239 |
+
|
| 1240 |
+
const links = []
|
| 1241 |
+
for (let i in results) {
|
| 1242 |
+
const result = results[i];
|
| 1243 |
+
if (result[0] === "urlkey") {
|
| 1244 |
+
continue
|
| 1245 |
+
}
|
| 1246 |
+
|
| 1247 |
+
const url = new URL(result[2])
|
| 1248 |
+
const base = url.hostname + url.pathname
|
| 1249 |
+
|
| 1250 |
+
links.push([base, result[2], result[1], `https://web.archive.org/web/${result[1]}/${result[2]}`])
|
| 1251 |
+
}
|
| 1252 |
+
|
| 1253 |
+
if (links.length) {
|
| 1254 |
+
links.sort(function (a,b) {
|
| 1255 |
+
// url base
|
| 1256 |
+
if (a[0] < b[0]) return -1
|
| 1257 |
+
if (a[0] > b[0]) return 1
|
| 1258 |
+
|
| 1259 |
+
// timestamp
|
| 1260 |
+
return b[2] - a[2]
|
| 1261 |
+
})
|
| 1262 |
+
|
| 1263 |
+
const hideOlder = $("#checkHideOlder").is(":checked")
|
| 1264 |
+
|
| 1265 |
+
function formatTime(waybackTime) {
|
| 1266 |
+
return waybackTime.replace(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/, "$1-$2-$3 $4:$5:$6")
|
| 1267 |
+
}
|
| 1268 |
+
|
| 1269 |
+
let currentBase = null;
|
| 1270 |
+
const linkHtml = []
|
| 1271 |
+
for (let i in links) {
|
| 1272 |
+
const link = links[i];
|
| 1273 |
+
|
| 1274 |
+
if (link[0] === currentBase) {
|
| 1275 |
+
linkHtml.push(`<li class="cdx-link wayback-cdx-older" ${hideOlder ? "style='display:none'" : ""}>
|
| 1276 |
+
<a target="_blank" href="${link[3]}">Archive.org - ${link[0]}</a> <small class="text-muted">${formatTime(link[2])}</small></li>`)
|
| 1277 |
+
continue
|
| 1278 |
+
}
|
| 1279 |
+
|
| 1280 |
+
currentBase = link[0]
|
| 1281 |
+
linkHtml.push(`<li class="cdx-link wayback-cdx-newest"><a target="_blank" href="${link[3]}">Archive.org - ${link[0]}</a> <small class="text-muted">${formatTime(link[2])}</small></li>`)
|
| 1282 |
+
}
|
| 1283 |
+
$("#wayback-append").html(`<ul>${linkHtml.join("")}</ul>`)
|
| 1284 |
+
$("#wayback-show-older,#wayback-copy").show();
|
| 1285 |
+
$("#wayback-show-older .older-count").text($(".wayback-cdx-older").length)
|
| 1286 |
+
} else {
|
| 1287 |
+
$("#wayback-append").text("No cdx records were found.")
|
| 1288 |
+
}
|
| 1289 |
+
})
|
| 1290 |
+
}
|
| 1291 |
+
}
|
| 1292 |
+
|
| 1293 |
+
function parseType(partMapType, sectionId, res, parsedInput) {
|
| 1294 |
+
if (res && res.items && res.items.length > 0) {
|
| 1295 |
+
const item = res.items[0];
|
| 1296 |
+
|
| 1297 |
+
exportData[partMapType] = res;
|
| 1298 |
+
|
| 1299 |
+
for (let part in partMap[partMapType]) {
|
| 1300 |
+
const section = $("#" + sectionId + " #" + part);
|
| 1301 |
+
const sectionHeader = $(section.find(".section-header"));
|
| 1302 |
+
|
| 1303 |
+
if (item.hasOwnProperty(part) && !$.isEmptyObject(item[part])) {
|
| 1304 |
+
sectionHeader.removeClass("unknown").addClass("good");
|
| 1305 |
+
sectionHeader.find("i").removeClass("bi-question-circle-fill").addClass("bi-check-circle-fill");
|
| 1306 |
+
} else {
|
| 1307 |
+
sectionHeader.removeClass("unknown").addClass("bad");
|
| 1308 |
+
sectionHeader.find("i").removeClass("bi-question-circle-fill").addClass("bi-dash-circle-fill");
|
| 1309 |
+
}
|
| 1310 |
+
|
| 1311 |
+
if (item.hasOwnProperty(part)) {
|
| 1312 |
+
if (part === 'localizations') {
|
| 1313 |
+
item[part] = shared.sortObject(item[part]);
|
| 1314 |
+
}
|
| 1315 |
+
|
| 1316 |
+
section.append("<pre><code class='prettyprint language-json'></code></pre>");
|
| 1317 |
+
|
| 1318 |
+
const json = section.find("code");
|
| 1319 |
+
json.text(JSON.stringify(item[part], null, 4));
|
| 1320 |
+
hljs.highlightElement(json[0]);
|
| 1321 |
+
|
| 1322 |
+
partMap[partMapType][part].postProcess(item[part], item);
|
| 1323 |
+
}
|
| 1324 |
+
|
| 1325 |
+
if (!item.hasOwnProperty(part) || $.isEmptyObject(item[part])) {
|
| 1326 |
+
section.append("<p class='mb-15 bad'>The " + partMapType + " does not have " + part + ".</p>");
|
| 1327 |
+
}
|
| 1328 |
+
}
|
| 1329 |
+
} else {
|
| 1330 |
+
errorState("Your input looked like a <span class='orange'>" + partMapType + "</span> but nothing came back. " +
|
| 1331 |
+
"It may have been <a target='_blank' href='https://github.com/mattwright324/youtube-metadata/wiki/Deleted-and-Private-Videos'>deleted or made private</a>.", function (append) {
|
| 1332 |
+
append.append("<p class='mb-15'>" +
|
| 1333 |
+
"You may find more details by trying..." +
|
| 1334 |
+
getSuggestedHtml(parsedInput) +
|
| 1335 |
+
"</p>");
|
| 1336 |
+
});
|
| 1337 |
+
attemptLoadFilmot(parsedInput);
|
| 1338 |
+
$("#wayback,#wayback-check").show()
|
| 1339 |
+
$("#wayback-append").html("")
|
| 1340 |
+
}
|
| 1341 |
+
}
|
| 1342 |
+
|
| 1343 |
+
async function parseVideo(res, input, skipGetChannel) {
|
| 1344 |
+
const channelId = shared.idx(["items", "0", "snippet", "channelId"], res)
|
| 1345 |
+
if (!skipGetChannel && channelId) {
|
| 1346 |
+
submit({
|
| 1347 |
+
type: 'channel_id',
|
| 1348 |
+
value: channelId,
|
| 1349 |
+
mayHideOthers: false
|
| 1350 |
+
});
|
| 1351 |
+
}
|
| 1352 |
+
|
| 1353 |
+
parseType("video", "video-section", res, input);
|
| 1354 |
+
|
| 1355 |
+
const id = input.value;
|
| 1356 |
+
const thumbsDiv = $("#thumbnails");
|
| 1357 |
+
|
| 1358 |
+
thumbsDiv.empty();
|
| 1359 |
+
const names = ["0", "hq1", "hq2", "hq3"]
|
| 1360 |
+
for (let i in names) {
|
| 1361 |
+
const name = names[i]
|
| 1362 |
+
const thumbUrl = "https://img.youtube.com/vi/" + id + "/" + name + ".jpg";
|
| 1363 |
+
const html =
|
| 1364 |
+
"<div class='column' style='margin-bottom: 1.5%!important;'>" +
|
| 1365 |
+
"<a href='https://lens.google.com/uploadbyurl?url=" + thumbUrl + "' target='_blank'>" +
|
| 1366 |
+
"<img id='video-thumb-" + name + "' src='" + thumbUrl + "' alt='Thumb " + name + "' style='max-width: 200px;'>" +
|
| 1367 |
+
"<p>Click to reverse image search</p>" +
|
| 1368 |
+
"</a>" +
|
| 1369 |
+
"</div>";
|
| 1370 |
+
|
| 1371 |
+
thumbsDiv.append(html);
|
| 1372 |
+
}
|
| 1373 |
+
|
| 1374 |
+
const videoMore = $("#video-more");
|
| 1375 |
+
videoMore.empty();
|
| 1376 |
+
videoMore.append(getSuggestedHtml(null, shared.idx(["items", 0], res), "video"));
|
| 1377 |
+
}
|
| 1378 |
+
|
| 1379 |
+
async function parsePlaylist(res, input, skipGetChannel) {
|
| 1380 |
+
const channelId = shared.idx(["items", "0", "snippet", "channelId"], res)
|
| 1381 |
+
if (!skipGetChannel && channelId) {
|
| 1382 |
+
submit({
|
| 1383 |
+
type: 'channel_id',
|
| 1384 |
+
value: channelId,
|
| 1385 |
+
mayHideOthers: false
|
| 1386 |
+
});
|
| 1387 |
+
}
|
| 1388 |
+
|
| 1389 |
+
parseType("playlist", "playlist-section", res, input);
|
| 1390 |
+
|
| 1391 |
+
const playlistMore = $("#playlist-more");
|
| 1392 |
+
playlistMore.empty();
|
| 1393 |
+
playlistMore.append(getSuggestedHtml(null, shared.idx(["items", 0], res), "playlist"));
|
| 1394 |
+
}
|
| 1395 |
+
|
| 1396 |
+
async function parseChannel(res, input) {
|
| 1397 |
+
parseType("channel", "channel-section", res, input);
|
| 1398 |
+
|
| 1399 |
+
const channelMore = $("#channel-more");
|
| 1400 |
+
channelMore.empty();
|
| 1401 |
+
channelMore.append(getSuggestedHtml(null, shared.idx(["items", 0], res), "channel"));
|
| 1402 |
+
}
|
| 1403 |
+
|
| 1404 |
+
/**
|
| 1405 |
+
* Attempt to resolve the channel handle URL via CORS workaround. Grab webpage content and extract url pattern.
|
| 1406 |
+
*/
|
| 1407 |
+
async function resolveChannelHandleCORS(parsedInput, callbackResubmit) {
|
| 1408 |
+
console.log('Attempting to resolve custom channel via CORS')
|
| 1409 |
+
|
| 1410 |
+
$.ajax({
|
| 1411 |
+
url: "https://cors-proxy-mw324.herokuapp.com/https://www.youtube.com/@" + parsedInput.value,
|
| 1412 |
+
dataType: 'html'
|
| 1413 |
+
}).then(function (res) {
|
| 1414 |
+
const pageHtml = $("<div>").html(res);
|
| 1415 |
+
const channelId = pageHtml.find("meta[itemprop='channelId']").attr('content');
|
| 1416 |
+
const ogUrl = pageHtml.find("meta[property='og:url']").attr('content');
|
| 1417 |
+
const canonical = pageHtml.find("link[rel='canonical']").attr('href');
|
| 1418 |
+
|
| 1419 |
+
console.log('Retrieved [channelId=%s, ogUrl=%s, canonical=%s]', channelId, ogUrl, canonical);
|
| 1420 |
+
|
| 1421 |
+
const newParsed = shared.determineInput(channelId || ogUrl || canonical);
|
| 1422 |
+
if (newParsed.type !== "unknown") {
|
| 1423 |
+
callbackResubmit(newParsed);
|
| 1424 |
+
} else {
|
| 1425 |
+
errorState("Could not resolve Custom Channel URL", function (append) {
|
| 1426 |
+
append.append("<p class='mb-15'>" +
|
| 1427 |
+
"Custom channel URLs have no direct API method, an indirect resolving method was unable to find it. " +
|
| 1428 |
+
"</p>");
|
| 1429 |
+
append.append("<p class='mb-15'>" +
|
| 1430 |
+
"Verify that the custom URL actually exists, if it does than you may try manually resolving it. " +
|
| 1431 |
+
"</p>");
|
| 1432 |
+
append.append("<p class='mb-15'>" +
|
| 1433 |
+
"More detail about the issue and what you can do can be found here at " +
|
| 1434 |
+
"<a target='_blank' href='https://github.com/mattwright324/youtube-metadata/issues/1'>#1 - Channel custom url unsupported</a>." +
|
| 1435 |
+
"</p>");
|
| 1436 |
+
})
|
| 1437 |
+
}
|
| 1438 |
+
}).fail(function (err) {
|
| 1439 |
+
errorState("Could not resolve Custom Channel URL", function (append) {
|
| 1440 |
+
append.append("<p class='mb-15'>" +
|
| 1441 |
+
"Custom channel URLs have no direct API method, an indirect resolving method was unable to find it. " +
|
| 1442 |
+
"</p>");
|
| 1443 |
+
append.append("<p class='mb-15'>" +
|
| 1444 |
+
"Verify that the custom URL actually exists, if it does than you may try manually resolving it. " +
|
| 1445 |
+
"</p>");
|
| 1446 |
+
append.append("<p class='mb-15'>" +
|
| 1447 |
+
"More detail about the issue and what you can do can be found here at " +
|
| 1448 |
+
"<a target='_blank' href='https://github.com/mattwright324/youtube-metadata/issues/1'>#1 - Channel custom url unsupported</a>." +
|
| 1449 |
+
"</p>");
|
| 1450 |
+
})
|
| 1451 |
+
});
|
| 1452 |
+
}
|
| 1453 |
+
|
| 1454 |
+
async function submit(parsedInput) {
|
| 1455 |
+
console.log(parsedInput);
|
| 1456 |
+
|
| 1457 |
+
if (parsedInput.original) {
|
| 1458 |
+
controls.inputValue.val(parsedInput.original);
|
| 1459 |
+
|
| 1460 |
+
const baseUrl = location.origin + location.pathname;
|
| 1461 |
+
if (parsedInput.type === "video_id" || parsedInput.type === "playlist_id" || parsedInput.type === "channel_id") {
|
| 1462 |
+
controls.shareLink.val(baseUrl + "?url=" + encodeURIComponent(parsedInput.original) + "&submit=true");
|
| 1463 |
+
} else {
|
| 1464 |
+
controls.shareLink.val(baseUrl + "?url=" + encodeURIComponent(parsedInput.original) + "&submit=true");
|
| 1465 |
+
}
|
| 1466 |
+
|
| 1467 |
+
controls.shareLink.attr("disabled", false);
|
| 1468 |
+
}
|
| 1469 |
+
|
| 1470 |
+
if (parsedInput.type === 'unknown') {
|
| 1471 |
+
errorState("Your link did not follow an accepted format.");
|
| 1472 |
+
} else if (parsedInput.type === 'channel_handle' || parsedInput.type === 'channel_custom') {
|
| 1473 |
+
resolveChannelHandleCORS(parsedInput, submit);
|
| 1474 |
+
} else if (parsedInput.type === 'video_id') {
|
| 1475 |
+
console.log('grabbing video');
|
| 1476 |
+
|
| 1477 |
+
if (parsedInput.mayHideOthers) {
|
| 1478 |
+
$("#playlist").hide();
|
| 1479 |
+
}
|
| 1480 |
+
|
| 1481 |
+
youtube.ajax('videos', {
|
| 1482 |
+
part: Object.keys(partMap.video).join(','),
|
| 1483 |
+
id: parsedInput.value
|
| 1484 |
+
}).done(function (res) {
|
| 1485 |
+
console.log(res);
|
| 1486 |
+
|
| 1487 |
+
parseVideo(res, parsedInput);
|
| 1488 |
+
}).fail(function (err) {
|
| 1489 |
+
console.log(err);
|
| 1490 |
+
|
| 1491 |
+
errorState("There was a problem querying for the video.", null, err);
|
| 1492 |
+
});
|
| 1493 |
+
} else if (parsedInput.type === 'channel_id') {
|
| 1494 |
+
console.log('grabbing channel id');
|
| 1495 |
+
|
| 1496 |
+
if (parsedInput.mayHideOthers) {
|
| 1497 |
+
$("#video,#playlist").hide();
|
| 1498 |
+
}
|
| 1499 |
+
|
| 1500 |
+
youtube.ajax('channels', {
|
| 1501 |
+
part: "id," + Object.keys(partMap.channel).join(','),
|
| 1502 |
+
id: parsedInput.value
|
| 1503 |
+
}).done(function (res) {
|
| 1504 |
+
console.log(res);
|
| 1505 |
+
|
| 1506 |
+
parseChannel(res, parsedInput);
|
| 1507 |
+
}).fail(function (err) {
|
| 1508 |
+
console.error(err);
|
| 1509 |
+
|
| 1510 |
+
errorState("There was a problem querying for the channel.", null, err);
|
| 1511 |
+
});
|
| 1512 |
+
} else if (parsedInput.type === 'channel_user') {
|
| 1513 |
+
console.log('grabbing channel user');
|
| 1514 |
+
|
| 1515 |
+
if (parsedInput.mayHideOthers) {
|
| 1516 |
+
$("#video,#playlist").hide();
|
| 1517 |
+
}
|
| 1518 |
+
|
| 1519 |
+
youtube.ajax('channels', {
|
| 1520 |
+
part: Object.keys(partMap.channel).join(','),
|
| 1521 |
+
forUsername: parsedInput.value
|
| 1522 |
+
}).done(function (res) {
|
| 1523 |
+
console.log(res);
|
| 1524 |
+
|
| 1525 |
+
parseChannel(res, parsedInput);
|
| 1526 |
+
}).fail(function (err) {
|
| 1527 |
+
console.error(err);
|
| 1528 |
+
|
| 1529 |
+
errorState("There was a problem querying for the channel.", null, err);
|
| 1530 |
+
});
|
| 1531 |
+
} else if (parsedInput.type === 'playlist_id') {
|
| 1532 |
+
console.log('grabbing playlist');
|
| 1533 |
+
|
| 1534 |
+
if (parsedInput.mayHideOthers) {
|
| 1535 |
+
$("#video").hide();
|
| 1536 |
+
}
|
| 1537 |
+
|
| 1538 |
+
youtube.ajax('playlists', {
|
| 1539 |
+
part: Object.keys(partMap.playlist).join(','),
|
| 1540 |
+
id: parsedInput.value
|
| 1541 |
+
}).done(function (res) {
|
| 1542 |
+
console.log(res);
|
| 1543 |
+
|
| 1544 |
+
parsePlaylist(res, parsedInput);
|
| 1545 |
+
}).fail(function (err) {
|
| 1546 |
+
console.error(err);
|
| 1547 |
+
|
| 1548 |
+
errorState("There was a problem querying for the playlist.", null, err);
|
| 1549 |
+
});
|
| 1550 |
+
}
|
| 1551 |
+
}
|
| 1552 |
+
|
| 1553 |
+
const internal = {
|
| 1554 |
+
init: function () {
|
| 1555 |
+
elements.hljsTheme = $("#highlightjs-theme");
|
| 1556 |
+
controls.darkMode = $("#darkMode");
|
| 1557 |
+
controls.inputValue = $("#value");
|
| 1558 |
+
controls.btnSubmit = $("#submit");
|
| 1559 |
+
controls.shareLink = $("#shareLink");
|
| 1560 |
+
|
| 1561 |
+
new ClipboardJS(".clipboard");
|
| 1562 |
+
|
| 1563 |
+
controls.btnExport = $("#export");
|
| 1564 |
+
controls.btnImport = $("#import");
|
| 1565 |
+
controls.importFileChooser = $("#importFileChooser");
|
| 1566 |
+
|
| 1567 |
+
elements.videoSection = $("#video-section");
|
| 1568 |
+
elements.channelSection = $("#channel-section");
|
| 1569 |
+
elements.playlistSection = $("#playlist-section");
|
| 1570 |
+
|
| 1571 |
+
const randomVideoId = shared.randomFromList(EXAMPLE_VIDEOS);
|
| 1572 |
+
const exampleLink = "https://youtu.be/" + randomVideoId;
|
| 1573 |
+
controls.inputValue.val(exampleLink);
|
| 1574 |
+
|
| 1575 |
+
internal.buildPage(true);
|
| 1576 |
+
},
|
| 1577 |
+
buildPage: function (doSetup) {
|
| 1578 |
+
$(".part-section").remove();
|
| 1579 |
+
$("#thumbnails").empty();
|
| 1580 |
+
|
| 1581 |
+
for (let part in partMap.video) {
|
| 1582 |
+
const partData = partMap.video[part];
|
| 1583 |
+
const html =
|
| 1584 |
+
"<div id='" + part + "' class='part-section'>" +
|
| 1585 |
+
"<div class='section-header unknown'><i class='bi bi-question-circle-fill'></i><span>" + partData.title + "</span></div>" +
|
| 1586 |
+
"</div>";
|
| 1587 |
+
elements.videoSection.append(html);
|
| 1588 |
+
}
|
| 1589 |
+
|
| 1590 |
+
for (let part in partMap.channel) {
|
| 1591 |
+
const partData = partMap.channel[part];
|
| 1592 |
+
const html =
|
| 1593 |
+
"<div id='" + part + "' class='part-section'>" +
|
| 1594 |
+
"<div class='section-header unknown'><i class='bi bi-question-circle-fill'></i><span>" + partData.title + "</span></div>" +
|
| 1595 |
+
"</div>";
|
| 1596 |
+
elements.channelSection.append(html);
|
| 1597 |
+
}
|
| 1598 |
+
|
| 1599 |
+
for (let part in partMap.playlist) {
|
| 1600 |
+
const partData = partMap.playlist[part];
|
| 1601 |
+
const html =
|
| 1602 |
+
"<div id='" + part + "' class='part-section'>" +
|
| 1603 |
+
"<div class='section-header unknown'><i class='bi bi-question-circle-fill'></i></i><span>" + partData.title + "</span></div>" +
|
| 1604 |
+
"</div>";
|
| 1605 |
+
elements.playlistSection.append(html);
|
| 1606 |
+
}
|
| 1607 |
+
|
| 1608 |
+
if (doSetup) {
|
| 1609 |
+
internal.setupControls();
|
| 1610 |
+
}
|
| 1611 |
+
},
|
| 1612 |
+
setupControls: function () {
|
| 1613 |
+
function checkTheme() {
|
| 1614 |
+
if (DarkMode.getColorScheme() === "dark") {
|
| 1615 |
+
elements.hljsTheme.attr("href", "//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.3.1/build/styles/stackoverflow-dark.min.css");
|
| 1616 |
+
} else {
|
| 1617 |
+
elements.hljsTheme.attr("href", "//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.3.1/build/styles/stackoverflow-light.min.css")
|
| 1618 |
+
}
|
| 1619 |
+
}
|
| 1620 |
+
|
| 1621 |
+
controls.darkMode.change(function () {
|
| 1622 |
+
checkTheme();
|
| 1623 |
+
});
|
| 1624 |
+
checkTheme();
|
| 1625 |
+
|
| 1626 |
+
controls.inputValue.on('keypress', function (e) {
|
| 1627 |
+
if (e.originalEvent.code === "Enter") {
|
| 1628 |
+
controls.btnSubmit.click();
|
| 1629 |
+
}
|
| 1630 |
+
});
|
| 1631 |
+
|
| 1632 |
+
countdownCheck(delaySubmitKey, controls.btnSubmit, delay5SecMs, "submit");
|
| 1633 |
+
|
| 1634 |
+
controls.btnSubmit.on('click', function () {
|
| 1635 |
+
if (!can.submit) {
|
| 1636 |
+
return;
|
| 1637 |
+
}
|
| 1638 |
+
localStorage.setItem(delaySubmitKey, new Date());
|
| 1639 |
+
countdownCheck(delaySubmitKey, controls.btnSubmit, delay5SecMs, "submit");
|
| 1640 |
+
|
| 1641 |
+
exportData = {};
|
| 1642 |
+
|
| 1643 |
+
const value = controls.inputValue.val();
|
| 1644 |
+
|
| 1645 |
+
const baseUrl = location.origin + location.pathname;
|
| 1646 |
+
controls.shareLink.val(baseUrl + "?url=" + encodeURIComponent(value) + "&submit=true");
|
| 1647 |
+
controls.shareLink.attr("disabled", false);
|
| 1648 |
+
|
| 1649 |
+
const parsed = shared.determineInput(value);
|
| 1650 |
+
window["parsed"] = parsed
|
| 1651 |
+
|
| 1652 |
+
$("#video,#playlist,#channel").show();
|
| 1653 |
+
$("#unknown,#quota,#filmot,#wayback").hide();
|
| 1654 |
+
internal.buildPage(false);
|
| 1655 |
+
submit(parsed);
|
| 1656 |
+
});
|
| 1657 |
+
|
| 1658 |
+
$("#wayback-check").click(function () {
|
| 1659 |
+
if ($("#wayback").is(":visible")) {
|
| 1660 |
+
$("#wayback-check").hide()
|
| 1661 |
+
attemptWaybackCDX(window.parsed);
|
| 1662 |
+
}
|
| 1663 |
+
})
|
| 1664 |
+
|
| 1665 |
+
$("#checkHideOlder").change(function () {
|
| 1666 |
+
if ($("#checkHideOlder").is(":checked")) {
|
| 1667 |
+
$(".wayback-cdx-older").hide()
|
| 1668 |
+
} else {
|
| 1669 |
+
$(".wayback-cdx-older").show()
|
| 1670 |
+
}
|
| 1671 |
+
})
|
| 1672 |
+
|
| 1673 |
+
new ClipboardJS("#wayback-copy", {
|
| 1674 |
+
text: function (trigger) {
|
| 1675 |
+
const links = []
|
| 1676 |
+
$(".cdx-link:visible").each(function (i, el) {
|
| 1677 |
+
const link = $(el).find("a").attr("href")
|
| 1678 |
+
if (link) {
|
| 1679 |
+
links.push(link)
|
| 1680 |
+
}
|
| 1681 |
+
})
|
| 1682 |
+
return links.join("\n")
|
| 1683 |
+
}
|
| 1684 |
+
})
|
| 1685 |
+
|
| 1686 |
+
function getImageBinaryCorsProxy(fileName, imageUrl, zip) {
|
| 1687 |
+
return new Promise(function (resolve) {
|
| 1688 |
+
// CORS proxy workaround for downloading YouTube thumbnails in client-side app
|
| 1689 |
+
// https://github.com/Rob--W/cors-anywhere/issues/301#issuecomment-962623118
|
| 1690 |
+
console.log('Attempting to download image over CORS proxy: ' + imageUrl);
|
| 1691 |
+
const start = new Date();
|
| 1692 |
+
JSZipUtils.getBinaryContent("https://cors-proxy-mw324.herokuapp.com/" + imageUrl, function (err, data) {
|
| 1693 |
+
const ms = new Date() - start;
|
| 1694 |
+
|
| 1695 |
+
if (err) {
|
| 1696 |
+
console.log('Failed ' + fileName + " (" + ms + "ms)");
|
| 1697 |
+
console.warn("Could not get image: " + imageUrl)
|
| 1698 |
+
console.warn(err);
|
| 1699 |
+
} else {
|
| 1700 |
+
console.log('Retrieved ' + fileName + " (" + ms + "ms)");
|
| 1701 |
+
console.log("Creating " + fileName + "...");
|
| 1702 |
+
zip.file(fileName, data, {binary: true});
|
| 1703 |
+
}
|
| 1704 |
+
|
| 1705 |
+
resolve();
|
| 1706 |
+
});
|
| 1707 |
+
});
|
| 1708 |
+
}
|
| 1709 |
+
|
| 1710 |
+
controls.btnExport.on('click', async function () {
|
| 1711 |
+
controls.btnExport.addClass("loading").addClass("disabled");
|
| 1712 |
+
|
| 1713 |
+
const zip = new JSZip();
|
| 1714 |
+
console.log("Creating about.txt...")
|
| 1715 |
+
zip.file("about.txt",
|
| 1716 |
+
"Downloaded by YouTube Metadata " + new Date().toLocaleString() + "\n\n" +
|
| 1717 |
+
"URL: " + window.location + "\n\n" +
|
| 1718 |
+
"Input: " + controls.inputValue.val()
|
| 1719 |
+
);
|
| 1720 |
+
|
| 1721 |
+
const thumbLinks = {};
|
| 1722 |
+
if (exportData.hasOwnProperty("video")) {
|
| 1723 |
+
console.log("Creating video.json...");
|
| 1724 |
+
zip.file("video.json", JSON.stringify(exportData.video, null, 4));
|
| 1725 |
+
|
| 1726 |
+
const names = ["0", "hq1", "hq2", "hq3"]
|
| 1727 |
+
for (let i in names) {
|
| 1728 |
+
const name = names[i];
|
| 1729 |
+
|
| 1730 |
+
thumbLinks[`video-thumb-${name}.png`] = document.getElementById(`video-thumb-${name}`).src;
|
| 1731 |
+
}
|
| 1732 |
+
}
|
| 1733 |
+
|
| 1734 |
+
if (exportData.hasOwnProperty("playlist")) {
|
| 1735 |
+
console.log("Creating playlist.json...");
|
| 1736 |
+
zip.file("playlist.json", JSON.stringify(exportData.playlist, null, 4));
|
| 1737 |
+
|
| 1738 |
+
thumbLinks["playlist-thumb.png"] = document.getElementById('playlist-thumb').src;
|
| 1739 |
+
}
|
| 1740 |
+
|
| 1741 |
+
if (exportData.hasOwnProperty("channel")) {
|
| 1742 |
+
console.log("Creating channel.json...");
|
| 1743 |
+
zip.file("channel.json", JSON.stringify(exportData.channel, null, 4));
|
| 1744 |
+
|
| 1745 |
+
thumbLinks["channel-thumb.png"] = document.getElementById('channel-thumb').src;
|
| 1746 |
+
if (document.getElementById('channel-banner')) {
|
| 1747 |
+
thumbLinks["channel-banner.png"] = document.getElementById('channel-banner').src;
|
| 1748 |
+
}
|
| 1749 |
+
}
|
| 1750 |
+
|
| 1751 |
+
if (exportData.hasOwnProperty("filmot")) {
|
| 1752 |
+
console.log("Creating filmot.json...");
|
| 1753 |
+
zip.file("filmot.json", JSON.stringify(exportData.filmot, null, 4));
|
| 1754 |
+
}
|
| 1755 |
+
|
| 1756 |
+
const optionalImages = [];
|
| 1757 |
+
for (let fileName in thumbLinks) {
|
| 1758 |
+
optionalImages.push(getImageBinaryCorsProxy(fileName, thumbLinks[fileName], zip));
|
| 1759 |
+
}
|
| 1760 |
+
|
| 1761 |
+
Promise.all(optionalImages).then(function () {
|
| 1762 |
+
let hint = '';
|
| 1763 |
+
if (exportData.hasOwnProperty("video")) {
|
| 1764 |
+
hint = " (video-" + shared.idx(["items", 0, "snippet", "title"], exportData.video).substr(0, 15) + ")";
|
| 1765 |
+
} else if (exportData.hasOwnProperty("playlist")) {
|
| 1766 |
+
hint = " (playlist-" + shared.idx(["items", 0, "snippet", "title"], exportData.playlist).substr(0, 15) + ")";
|
| 1767 |
+
} else if (exportData.hasOwnProperty("channel")) {
|
| 1768 |
+
hint = " (channel-" + shared.idx(["items", 0, "snippet", "title"], exportData.channel).substr(0, 15) + ")";
|
| 1769 |
+
} else if (exportData.hasOwnProperty("filmot")) {
|
| 1770 |
+
hint = " (filmot-" + exportData.filmot.title.substr(0, 15);
|
| 1771 |
+
}
|
| 1772 |
+
|
| 1773 |
+
const fileName = shared.safeFileName("metadata" + hint + ".zip");
|
| 1774 |
+
console.log("Saving as " + fileName);
|
| 1775 |
+
zip.generateAsync({
|
| 1776 |
+
type: "blob",
|
| 1777 |
+
compression: "DEFLATE",
|
| 1778 |
+
compressionOptions: {
|
| 1779 |
+
level: 9
|
| 1780 |
+
}
|
| 1781 |
+
}).then(function (content) {
|
| 1782 |
+
saveAs(content, fileName);
|
| 1783 |
+
|
| 1784 |
+
controls.btnExport.removeClass("loading").removeClass("disabled");
|
| 1785 |
+
});
|
| 1786 |
+
});
|
| 1787 |
+
});
|
| 1788 |
+
|
| 1789 |
+
// Drag & Drop listener
|
| 1790 |
+
document.addEventListener("dragover", function (event) {
|
| 1791 |
+
event.preventDefault();
|
| 1792 |
+
});
|
| 1793 |
+
document.documentElement.addEventListener('drop', async function (e) {
|
| 1794 |
+
e.stopPropagation();
|
| 1795 |
+
e.preventDefault();
|
| 1796 |
+
|
| 1797 |
+
let file = e.dataTransfer.files[0];
|
| 1798 |
+
console.log("Loading file");
|
| 1799 |
+
console.log(file);
|
| 1800 |
+
|
| 1801 |
+
importFile(file);
|
| 1802 |
+
});
|
| 1803 |
+
|
| 1804 |
+
controls.importFileChooser.on('change', function (event) {
|
| 1805 |
+
console.log(event);
|
| 1806 |
+
|
| 1807 |
+
let file = event.target.files[0];
|
| 1808 |
+
|
| 1809 |
+
if (file) {
|
| 1810 |
+
controls.inputValue.val(file.name);
|
| 1811 |
+
} else {
|
| 1812 |
+
return;
|
| 1813 |
+
}
|
| 1814 |
+
|
| 1815 |
+
importFile(file);
|
| 1816 |
+
});
|
| 1817 |
+
|
| 1818 |
+
function importFile(file) {
|
| 1819 |
+
console.log("Importing from file " + file.name);
|
| 1820 |
+
|
| 1821 |
+
controls.btnImport.addClass("loading").addClass("disabled");
|
| 1822 |
+
|
| 1823 |
+
$("#video,#playlist,#channel").show();
|
| 1824 |
+
$("#unknown,#quota,#filmot,#wayback").hide();
|
| 1825 |
+
internal.buildPage(false);
|
| 1826 |
+
|
| 1827 |
+
function loadFile(fileName, parseMethod, inputType) {
|
| 1828 |
+
return JSZip.loadAsync(file).then(function (content) {
|
| 1829 |
+
const file = content.file(fileName);
|
| 1830 |
+
return file ? file.async("string") : null;
|
| 1831 |
+
}).then(function (text) {
|
| 1832 |
+
if (!text) {
|
| 1833 |
+
$("#" + inputType).hide();
|
| 1834 |
+
return;
|
| 1835 |
+
}
|
| 1836 |
+
const content = JSON.parse(text);
|
| 1837 |
+
console.log(content);
|
| 1838 |
+
parseMethod(content, {
|
| 1839 |
+
type: inputType,
|
| 1840 |
+
value: shared.idx(["items", 0, "id"], content)
|
| 1841 |
+
}, true);
|
| 1842 |
+
});
|
| 1843 |
+
}
|
| 1844 |
+
|
| 1845 |
+
loadFile("video.json", parseVideo, "video").then(function () {
|
| 1846 |
+
loadFile("playlist.json", parsePlaylist, "playlist").then(function () {
|
| 1847 |
+
loadFile("channel.json", parseChannel, "channel").then(function () {
|
| 1848 |
+
controls.btnImport.removeClass("loading").removeClass("disabled");
|
| 1849 |
+
})
|
| 1850 |
+
});
|
| 1851 |
+
});
|
| 1852 |
+
}
|
| 1853 |
+
|
| 1854 |
+
const query = shared.parseQuery(window.location.search);
|
| 1855 |
+
console.log(query);
|
| 1856 |
+
const input = query.url || query.id;
|
| 1857 |
+
if (input) {
|
| 1858 |
+
controls.inputValue.val(decodeURIComponent(input));
|
| 1859 |
+
}
|
| 1860 |
+
if (query.hasOwnProperty("submit") && String(query.submit).toLowerCase() === String(true)) {
|
| 1861 |
+
setTimeout(function () {
|
| 1862 |
+
controls.btnSubmit.click();
|
| 1863 |
+
}, 500);
|
| 1864 |
+
}
|
| 1865 |
+
}
|
| 1866 |
+
};
|
| 1867 |
+
$(document).ready(internal.init);
|
| 1868 |
+
}());
|
js/yt-category-translator.js
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Implementation to quickly translate YouTube category codes.
|
| 3 |
+
*
|
| 4 |
+
* @link https://developers.google.com/youtube/v3/docs/videoCategories/list?apix_params=%7B%22part%22%3A%5B%22snippet%22%5D%2C%22regionCode%22%3A%22US%22%7D
|
| 5 |
+
*/
|
| 6 |
+
const ytCategory = (function () {
|
| 7 |
+
'use strict';
|
| 8 |
+
|
| 9 |
+
const categories = [
|
| 10 |
+
{
|
| 11 |
+
"kind": "youtube#videoCategory",
|
| 12 |
+
"etag": "grPOPYEUUZN3ltuDUGEWlrTR90U",
|
| 13 |
+
"id": "1",
|
| 14 |
+
"snippet": {
|
| 15 |
+
"title": "Film & Animation",
|
| 16 |
+
"assignable": true,
|
| 17 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"kind": "youtube#videoCategory",
|
| 22 |
+
"etag": "Q0xgUf8BFM8rW3W0R9wNq809xyA",
|
| 23 |
+
"id": "2",
|
| 24 |
+
"snippet": {
|
| 25 |
+
"title": "Autos & Vehicles",
|
| 26 |
+
"assignable": true,
|
| 27 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 28 |
+
}
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"kind": "youtube#videoCategory",
|
| 32 |
+
"etag": "qnpwjh5QlWM5hrnZCvHisquztC4",
|
| 33 |
+
"id": "10",
|
| 34 |
+
"snippet": {
|
| 35 |
+
"title": "Music",
|
| 36 |
+
"assignable": true,
|
| 37 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 38 |
+
}
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"kind": "youtube#videoCategory",
|
| 42 |
+
"etag": "HyFIixS5BZaoBdkQdLzPdoXWipg",
|
| 43 |
+
"id": "15",
|
| 44 |
+
"snippet": {
|
| 45 |
+
"title": "Pets & Animals",
|
| 46 |
+
"assignable": true,
|
| 47 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 48 |
+
}
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"kind": "youtube#videoCategory",
|
| 52 |
+
"etag": "PNU8SwXhjsF90fmkilVohofOi4I",
|
| 53 |
+
"id": "17",
|
| 54 |
+
"snippet": {
|
| 55 |
+
"title": "Sports",
|
| 56 |
+
"assignable": true,
|
| 57 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 58 |
+
}
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"kind": "youtube#videoCategory",
|
| 62 |
+
"etag": "5kFljz9YJ4lEgSfVwHWi5kTAwAs",
|
| 63 |
+
"id": "18",
|
| 64 |
+
"snippet": {
|
| 65 |
+
"title": "Short Movies",
|
| 66 |
+
"assignable": false,
|
| 67 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 68 |
+
}
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"kind": "youtube#videoCategory",
|
| 72 |
+
"etag": "ANnLQyzEA_9m3bMyJXMhKTCOiyg",
|
| 73 |
+
"id": "19",
|
| 74 |
+
"snippet": {
|
| 75 |
+
"title": "Travel & Events",
|
| 76 |
+
"assignable": true,
|
| 77 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 78 |
+
}
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"kind": "youtube#videoCategory",
|
| 82 |
+
"etag": "0Hh6gbZ9zWjnV3sfdZjKB5LQr6E",
|
| 83 |
+
"id": "20",
|
| 84 |
+
"snippet": {
|
| 85 |
+
"title": "Gaming",
|
| 86 |
+
"assignable": true,
|
| 87 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 88 |
+
}
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"kind": "youtube#videoCategory",
|
| 92 |
+
"etag": "q8Cp4pUfCD8Fuh8VJ_yl5cBCVNw",
|
| 93 |
+
"id": "21",
|
| 94 |
+
"snippet": {
|
| 95 |
+
"title": "Videoblogging",
|
| 96 |
+
"assignable": false,
|
| 97 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 98 |
+
}
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"kind": "youtube#videoCategory",
|
| 102 |
+
"etag": "cHDaaqPDZsJT1FPr1-MwtyIhR28",
|
| 103 |
+
"id": "22",
|
| 104 |
+
"snippet": {
|
| 105 |
+
"title": "People & Blogs",
|
| 106 |
+
"assignable": true,
|
| 107 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 108 |
+
}
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"kind": "youtube#videoCategory",
|
| 112 |
+
"etag": "3Uz364xBbKY50a2s0XQlv-gXJds",
|
| 113 |
+
"id": "23",
|
| 114 |
+
"snippet": {
|
| 115 |
+
"title": "Comedy",
|
| 116 |
+
"assignable": true,
|
| 117 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 118 |
+
}
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"kind": "youtube#videoCategory",
|
| 122 |
+
"etag": "0srcLUqQzO7-NGLF7QnhdVzJQmY",
|
| 123 |
+
"id": "24",
|
| 124 |
+
"snippet": {
|
| 125 |
+
"title": "Entertainment",
|
| 126 |
+
"assignable": true,
|
| 127 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 128 |
+
}
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"kind": "youtube#videoCategory",
|
| 132 |
+
"etag": "bQlQMjmYX7DyFkX4w3kT0osJyIc",
|
| 133 |
+
"id": "25",
|
| 134 |
+
"snippet": {
|
| 135 |
+
"title": "News & Politics",
|
| 136 |
+
"assignable": true,
|
| 137 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 138 |
+
}
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"kind": "youtube#videoCategory",
|
| 142 |
+
"etag": "Y06N41HP_WlZmeREZvkGF0HW5pg",
|
| 143 |
+
"id": "26",
|
| 144 |
+
"snippet": {
|
| 145 |
+
"title": "Howto & Style",
|
| 146 |
+
"assignable": true,
|
| 147 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 148 |
+
}
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"kind": "youtube#videoCategory",
|
| 152 |
+
"etag": "yBaNkLx4sX9NcDmFgAmxQcV4Y30",
|
| 153 |
+
"id": "27",
|
| 154 |
+
"snippet": {
|
| 155 |
+
"title": "Education",
|
| 156 |
+
"assignable": true,
|
| 157 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 158 |
+
}
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"kind": "youtube#videoCategory",
|
| 162 |
+
"etag": "Mxy3A-SkmnR7MhJDZRS4DuAIbQA",
|
| 163 |
+
"id": "28",
|
| 164 |
+
"snippet": {
|
| 165 |
+
"title": "Science & Technology",
|
| 166 |
+
"assignable": true,
|
| 167 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 168 |
+
}
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"kind": "youtube#videoCategory",
|
| 172 |
+
"etag": "p3lEirEJApyEkuWpaGEHoF-m-aA",
|
| 173 |
+
"id": "29",
|
| 174 |
+
"snippet": {
|
| 175 |
+
"title": "Nonprofits & Activism",
|
| 176 |
+
"assignable": true,
|
| 177 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 178 |
+
}
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
"kind": "youtube#videoCategory",
|
| 182 |
+
"etag": "4pIHL_AdN2kO7btAGAP1TvPucNk",
|
| 183 |
+
"id": "30",
|
| 184 |
+
"snippet": {
|
| 185 |
+
"title": "Movies",
|
| 186 |
+
"assignable": false,
|
| 187 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 188 |
+
}
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"kind": "youtube#videoCategory",
|
| 192 |
+
"etag": "Iqol1myDwh2AuOnxjtn2AfYwJTU",
|
| 193 |
+
"id": "31",
|
| 194 |
+
"snippet": {
|
| 195 |
+
"title": "Anime/Animation",
|
| 196 |
+
"assignable": false,
|
| 197 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 198 |
+
}
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"kind": "youtube#videoCategory",
|
| 202 |
+
"etag": "tzhBKCBcYWZLPai5INY4id91ss8",
|
| 203 |
+
"id": "32",
|
| 204 |
+
"snippet": {
|
| 205 |
+
"title": "Action/Adventure",
|
| 206 |
+
"assignable": false,
|
| 207 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 208 |
+
}
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"kind": "youtube#videoCategory",
|
| 212 |
+
"etag": "ii8nBGYpKyl6FyzP3cmBCevdrbs",
|
| 213 |
+
"id": "33",
|
| 214 |
+
"snippet": {
|
| 215 |
+
"title": "Classics",
|
| 216 |
+
"assignable": false,
|
| 217 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 218 |
+
}
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"kind": "youtube#videoCategory",
|
| 222 |
+
"etag": "Y0u9UAQCCGp60G11Arac5Mp46z4",
|
| 223 |
+
"id": "34",
|
| 224 |
+
"snippet": {
|
| 225 |
+
"title": "Comedy",
|
| 226 |
+
"assignable": false,
|
| 227 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 228 |
+
}
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"kind": "youtube#videoCategory",
|
| 232 |
+
"etag": "_YDnyT205AMuX8etu8loOiQjbD4",
|
| 233 |
+
"id": "35",
|
| 234 |
+
"snippet": {
|
| 235 |
+
"title": "Documentary",
|
| 236 |
+
"assignable": false,
|
| 237 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 238 |
+
}
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"kind": "youtube#videoCategory",
|
| 242 |
+
"etag": "eAl2b-uqIGRDgnlMa0EsGZjXmWg",
|
| 243 |
+
"id": "36",
|
| 244 |
+
"snippet": {
|
| 245 |
+
"title": "Drama",
|
| 246 |
+
"assignable": false,
|
| 247 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 248 |
+
}
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"kind": "youtube#videoCategory",
|
| 252 |
+
"etag": "HDAW2HFOt3SqeDI00X-eL7OELfY",
|
| 253 |
+
"id": "37",
|
| 254 |
+
"snippet": {
|
| 255 |
+
"title": "Family",
|
| 256 |
+
"assignable": false,
|
| 257 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 258 |
+
}
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
"kind": "youtube#videoCategory",
|
| 262 |
+
"etag": "QHiWh3niw5hjDrim85M8IGF45eE",
|
| 263 |
+
"id": "38",
|
| 264 |
+
"snippet": {
|
| 265 |
+
"title": "Foreign",
|
| 266 |
+
"assignable": false,
|
| 267 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"kind": "youtube#videoCategory",
|
| 272 |
+
"etag": "ztKcSS7GpH9uEyZk9nQCdNujvGg",
|
| 273 |
+
"id": "39",
|
| 274 |
+
"snippet": {
|
| 275 |
+
"title": "Horror",
|
| 276 |
+
"assignable": false,
|
| 277 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 278 |
+
}
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"kind": "youtube#videoCategory",
|
| 282 |
+
"etag": "Ids1sm8QFeSo_cDlpcUNrnEBYWA",
|
| 283 |
+
"id": "40",
|
| 284 |
+
"snippet": {
|
| 285 |
+
"title": "Sci-Fi/Fantasy",
|
| 286 |
+
"assignable": false,
|
| 287 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 288 |
+
}
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"kind": "youtube#videoCategory",
|
| 292 |
+
"etag": "qhfgS7MzzZHIy_UZ1dlawl1GbnY",
|
| 293 |
+
"id": "41",
|
| 294 |
+
"snippet": {
|
| 295 |
+
"title": "Thriller",
|
| 296 |
+
"assignable": false,
|
| 297 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 298 |
+
}
|
| 299 |
+
},
|
| 300 |
+
{
|
| 301 |
+
"kind": "youtube#videoCategory",
|
| 302 |
+
"etag": "TxVSfGoUyT7CJ7h7ebjg4vhIt6g",
|
| 303 |
+
"id": "42",
|
| 304 |
+
"snippet": {
|
| 305 |
+
"title": "Shorts",
|
| 306 |
+
"assignable": false,
|
| 307 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 308 |
+
}
|
| 309 |
+
},
|
| 310 |
+
{
|
| 311 |
+
"kind": "youtube#videoCategory",
|
| 312 |
+
"etag": "o9w6eNqzjHPnNbKDujnQd8pklXM",
|
| 313 |
+
"id": "43",
|
| 314 |
+
"snippet": {
|
| 315 |
+
"title": "Shows",
|
| 316 |
+
"assignable": false,
|
| 317 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 318 |
+
}
|
| 319 |
+
},
|
| 320 |
+
{
|
| 321 |
+
"kind": "youtube#videoCategory",
|
| 322 |
+
"etag": "mLdyKd0VgXKDI6GevTLBAcvRlIU",
|
| 323 |
+
"id": "44",
|
| 324 |
+
"snippet": {
|
| 325 |
+
"title": "Trailers",
|
| 326 |
+
"assignable": false,
|
| 327 |
+
"channelId": "UCBR8-60-B28hp2BmDPdntcQ"
|
| 328 |
+
}
|
| 329 |
+
}
|
| 330 |
+
];
|
| 331 |
+
|
| 332 |
+
return {
|
| 333 |
+
/**
|
| 334 |
+
* @param code video categoryId
|
| 335 |
+
* @returns category title
|
| 336 |
+
*/
|
| 337 |
+
lookup: function (code) {
|
| 338 |
+
if (!code) {
|
| 339 |
+
return;
|
| 340 |
+
}
|
| 341 |
+
for (let i = 0; i < categories.length; i++) {
|
| 342 |
+
const category = categories[i];
|
| 343 |
+
|
| 344 |
+
if (Number(category.id) === Number(code)) {
|
| 345 |
+
return category.snippet.title;
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
}
|
| 350 |
+
}());
|