Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- .gitignore +3 -0
- BUILD.md +53 -0
- CONTRIBUTING.md +15 -0
- Gemfile +2 -0
- LICENSE +21 -0
- PRIVACY.md +20 -0
- README.md +46 -10
- 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
|
README.md
CHANGED
|
@@ -1,10 +1,46 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# MW Metadata
|
| 2 |
+
|
| 3 |
+
A quick way to gather all the metadata about a video, playlist, or channel from the YouTube API.
|
| 4 |
+
|
| 5 |
+
- https://mattw.io/youtube-metadata/
|
| 6 |
+
- https://mattw.io/youtube-metadata/bulk
|
| 7 |
+
|
| 8 |
+

|
| 9 |
+
|
| 10 |
+
What's unique about this tool? How can you use it?
|
| 11 |
+
|
| 12 |
+
1. If you're curious about a video and its author, playlist and its creator, or channel
|
| 13 |
+
2. If you're curious about an entire playlist's videos or channel's videos
|
| 14 |
+
3. Use it as an API-explorer
|
| 15 |
+
- Grabs every part available
|
| 16 |
+
- Provides shareable link
|
| 17 |
+
4. Use it for investigative purposes and OSINT
|
| 18 |
+
- Tells you what if found and what it didn't find
|
| 19 |
+
- Auto-translations of language and country codes
|
| 20 |
+
- Geolocation direct link to Google Maps
|
| 21 |
+
- Interpretation and display of meaningful fields
|
| 22 |
+
- Reverse image search thumbnails
|
| 23 |
+
- Archive video and channel data that may disappear
|
| 24 |
+
5. Assist in finding private, deleted, and unlisted videos
|
| 25 |
+
- Option to inspect videos in a channel's created playlists to find unlisted videos
|
| 26 |
+
- Link to various resources with prefilled parameters: Archive.org, Filmot, SocialBlade, and Google
|
| 27 |
+
- Queries Filmot to see if it has data for private and deleted videos
|
| 28 |
+
6. Export and import
|
| 29 |
+
- Save data as a zip
|
| 30 |
+
- Import zip to view in app again later
|
| 31 |
+
- Both raw json data from the api and csv from the tables
|
| 32 |
+
|
| 33 |
+
## Wiki
|
| 34 |
+
|
| 35 |
+
For more details and notes about YouTube metadata and the API, [check out the wiki!](https://github.com/mattwright324/youtube-metadata/wiki)
|
| 36 |
+
|
| 37 |
+
## Build
|
| 38 |
+
|
| 39 |
+
Refer to [BUILD.md](https://github.com/mattwright324/youtube-metadata/blob/master/BUILD.md)
|
| 40 |
+
for instructions on how to build and run from source.
|
| 41 |
+
|
| 42 |
+
## Contributing
|
| 43 |
+
|
| 44 |
+
Contributions are welcome, refer
|
| 45 |
+
to [CONTRIBUTING.md](https://github.com/mattwright324/youtube-metadata/blob/master/CONTRIBUTING.md)
|
| 46 |
+
for more detail.
|
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 |
+
}());
|