mirror of
https://github.com/iptv-org/database.git
synced 2024-11-14 07:42:30 -05:00
Init
This commit is contained in:
commit
26d5bf0436
27 changed files with 43517 additions and 0 deletions
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: iptv-org
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
19
.github/workflows/check.yml
vendored
Normal file
19
.github/workflows/check.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
name: check
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, edited]
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- id: files
|
||||||
|
uses: tj-actions/changed-files@v12.2
|
||||||
|
with:
|
||||||
|
files: \.csv$
|
||||||
|
- name: validate
|
||||||
|
if: steps.files.outputs.any_changed == 'true'
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm run db:validate -- ${{ steps.files.outputs.all_changed_files }}
|
29
.github/workflows/deploy.yml
vendored
Normal file
29
.github/workflows/deploy.yml
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
name: deploy
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run db:export
|
||||||
|
- uses: tibdex/github-app-token@v1
|
||||||
|
if: ${{ !env.ACT }}
|
||||||
|
id: create-app-token
|
||||||
|
with:
|
||||||
|
app_id: ${{ secrets.APP_ID }}
|
||||||
|
private_key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||||
|
- uses: JamesIves/github-pages-deploy-action@4.1.1
|
||||||
|
if: ${{ !env.ACT }}
|
||||||
|
with:
|
||||||
|
branch: gh-pages
|
||||||
|
folder: .gh-pages
|
||||||
|
token: ${{ steps.create-app-token.outputs.token }}
|
||||||
|
git-config-name: iptv-bot[bot]
|
||||||
|
git-config-email: 84861620+iptv-bot[bot]@users.noreply.github.com
|
||||||
|
commit-message: '[Bot] Deploy to GitHub Pages'
|
||||||
|
clean: false
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/node_modules/
|
||||||
|
/.artifacts/
|
24
LICENSE
Normal file
24
LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
29
data/categories.csv
Normal file
29
data/categories.csv
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
id,name
|
||||||
|
auto,Auto
|
||||||
|
animation,Animation
|
||||||
|
business,Business
|
||||||
|
classic,Classic
|
||||||
|
comedy,Comedy
|
||||||
|
cooking,Cooking
|
||||||
|
culture,Culture
|
||||||
|
documentary,Documentary
|
||||||
|
education,Education
|
||||||
|
entertainment,Entertainment
|
||||||
|
family,Family
|
||||||
|
general,General
|
||||||
|
kids,Kids
|
||||||
|
legislative,Legislative
|
||||||
|
lifestyle,Lifestyle
|
||||||
|
movies,Movies
|
||||||
|
music,Music
|
||||||
|
news,News
|
||||||
|
outdoor,Outdoor
|
||||||
|
relax,Relax
|
||||||
|
religious,Religious
|
||||||
|
series,Series
|
||||||
|
science,Science
|
||||||
|
shop,Shop
|
||||||
|
sports,Sports
|
||||||
|
travel,Travel
|
||||||
|
weather,Weather
|
||||||
|
xxx,XXX
|
|
29797
data/channels.csv
Normal file
29797
data/channels.csv
Normal file
File diff suppressed because it is too large
Load diff
251
data/countries.csv
Normal file
251
data/countries.csv
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
name,code,lang,flag
|
||||||
|
Afghanistan,AF,pus,🇦🇫
|
||||||
|
Albania,AL,sqi,🇦🇱
|
||||||
|
Algeria,DZ,ara,🇩🇿
|
||||||
|
American Samoa,AS,eng,🇦🇸
|
||||||
|
Andorra,AD,cat,🇦🇩
|
||||||
|
Angola,AO,por,🇦🇴
|
||||||
|
Anguilla,AI,eng,🇦🇮
|
||||||
|
Antarctica,AQ,eng,🇦🇶
|
||||||
|
Antigua and Barbuda,AG,eng,🇦🇬
|
||||||
|
Argentina,AR,spa,🇦🇷
|
||||||
|
Armenia,AM,hye,🇦🇲
|
||||||
|
Aruba,AW,nld,🇦🇼
|
||||||
|
Australia,AU,eng,🇦🇺
|
||||||
|
Austria,AT,deu,🇦🇹
|
||||||
|
Azerbaijan,AZ,aze,🇦🇿
|
||||||
|
Bahamas,BS,eng,🇧🇸
|
||||||
|
Bahrain,BH,ara,🇧🇭
|
||||||
|
Bangladesh,BD,ben,🇧🇩
|
||||||
|
Barbados,BB,eng,🇧🇧
|
||||||
|
Belarus,BY,bel,🇧🇾
|
||||||
|
Belgium,BE,nld,🇧🇪
|
||||||
|
Belize,BZ,eng,🇧🇿
|
||||||
|
Benin,BJ,fra,🇧🇯
|
||||||
|
Bermuda,BM,eng,🇧🇲
|
||||||
|
Bhutan,BT,dzo,🇧🇹
|
||||||
|
Bolivia,BO,spa,🇧🇴
|
||||||
|
Bonaire,BQ,nld,🇧🇶
|
||||||
|
Bosnia and Herzegovina,BA,bos,🇧🇦
|
||||||
|
Botswana,BW,eng,🇧🇼
|
||||||
|
Bouvet Island,BV,nor,🇧🇻
|
||||||
|
Brazil,BR,por,🇧🇷
|
||||||
|
British Indian Ocean Territory,IO,eng,🇮🇴
|
||||||
|
British Virgin Islands,VG,eng,🇻🇬
|
||||||
|
Brunei,BN,msa,🇧🇳
|
||||||
|
Bulgaria,BG,bul,🇧🇬
|
||||||
|
Burkina Faso,BF,fra,🇧🇫
|
||||||
|
Burundi,BI,fra,🇧🇮
|
||||||
|
Cambodia,KH,khm,🇰🇭
|
||||||
|
Cameroon,CM,eng,🇨🇲
|
||||||
|
Canada,CA,eng,🇨🇦
|
||||||
|
Cape Verde,CV,por,🇨🇻
|
||||||
|
Cayman Islands,KY,eng,🇰🇾
|
||||||
|
Central African Republic,CF,fra,🇨🇫
|
||||||
|
Chad,TD,fra,🇹🇩
|
||||||
|
Chile,CL,spa,🇨🇱
|
||||||
|
China,CN,zho,🇨🇳
|
||||||
|
Christmas Island,CX,eng,🇨🇽
|
||||||
|
Cocos (Keeling) Islands,CC,eng,🇨🇨
|
||||||
|
Colombia,CO,spa,🇨🇴
|
||||||
|
Comoros,KM,ara,🇰🇲
|
||||||
|
Cook Islands,CK,eng,🇨🇰
|
||||||
|
Costa Rica,CR,spa,🇨🇷
|
||||||
|
Croatia,HR,hrv,🇭🇷
|
||||||
|
Cuba,CU,spa,🇨🇺
|
||||||
|
Curacao,CW,nld,🇨🇼
|
||||||
|
Cyprus,CY,ell,🇨🇾
|
||||||
|
Czech Republic,CZ,ces,🇨🇿
|
||||||
|
Democratic Republic of the Congo,CD,fra,🇨🇩
|
||||||
|
Denmark,DK,dan,🇩🇰
|
||||||
|
Djibouti,DJ,fra,🇩🇯
|
||||||
|
Dominica,DM,eng,🇩🇲
|
||||||
|
Dominican Republic,DO,spa,🇩🇴
|
||||||
|
East Timor,TL,por,🇹🇱
|
||||||
|
Ecuador,EC,spa,🇪🇨
|
||||||
|
Egypt,EG,ara,🇪🇬
|
||||||
|
El Salvador,SV,spa,🇸🇻
|
||||||
|
Equatorial Guinea,GQ,spa,🇬🇶
|
||||||
|
Eritrea,ER,tir,🇪🇷
|
||||||
|
Estonia,EE,est,🇪🇪
|
||||||
|
Ethiopia,ET,amh,🇪🇹
|
||||||
|
Falkland Islands,FK,eng,🇫🇰
|
||||||
|
Faroe Islands,FO,fao,🇫🇴
|
||||||
|
Fiji,FJ,eng,🇫🇯
|
||||||
|
Finland,FI,fin,🇫🇮
|
||||||
|
France,FR,fra,🇫🇷
|
||||||
|
French Guiana,GF,fra,🇬🇫
|
||||||
|
French Polynesia,PF,fra,🇵🇫
|
||||||
|
French Southern Territories,TF,fra,🇹🇫
|
||||||
|
Gabon,GA,fra,🇬🇦
|
||||||
|
Gambia,GM,eng,🇬🇲
|
||||||
|
Georgia,GE,kat,🇬🇪
|
||||||
|
Germany,DE,deu,🇩🇪
|
||||||
|
Ghana,GH,eng,🇬🇭
|
||||||
|
Gibraltar,GI,eng,🇬🇮
|
||||||
|
Greece,GR,ell,🇬🇷
|
||||||
|
Greenland,GL,kal,🇬🇱
|
||||||
|
Grenada,GD,eng,🇬🇩
|
||||||
|
Guadeloupe,GP,fra,🇬🇵
|
||||||
|
Guam,GU,eng,🇬🇺
|
||||||
|
Guatemala,GT,spa,🇬🇹
|
||||||
|
Guernsey,GG,eng,🇬🇬
|
||||||
|
Guinea,GN,fra,🇬🇳
|
||||||
|
Guinea-Bissau,GW,por,🇬🇼
|
||||||
|
Guyana,GY,eng,🇬🇾
|
||||||
|
Haiti,HT,fra,🇭🇹
|
||||||
|
Heard Island and McDonald Islands,HM,eng,🇭🇲
|
||||||
|
Honduras,HN,spa,🇭🇳
|
||||||
|
Hong Kong,HK,zho,🇭🇰
|
||||||
|
Hungary,HU,hun,🇭🇺
|
||||||
|
Iceland,IS,isl,🇮🇸
|
||||||
|
India,IN,hin,🇮🇳
|
||||||
|
Indonesia,ID,ind,🇮🇩
|
||||||
|
Iran,IR,fas,🇮🇷
|
||||||
|
Iraq,IQ,ara,🇮🇶
|
||||||
|
Ireland,IE,gle,🇮🇪
|
||||||
|
Isle of Man,IM,eng,🇮🇲
|
||||||
|
Israel,IL,heb,🇮🇱
|
||||||
|
Italy,IT,ita,🇮🇹
|
||||||
|
Ivory Coast,CI,fra,🇨🇮
|
||||||
|
Jamaica,JM,eng,🇯🇲
|
||||||
|
Japan,JP,jpn,🇯🇵
|
||||||
|
Jersey,JE,eng,🇯🇪
|
||||||
|
Jordan,JO,ara,🇯🇴
|
||||||
|
Kazakhstan,KZ,kaz,🇰🇿
|
||||||
|
Kenya,KE,eng,🇰🇪
|
||||||
|
Kiribati,KI,eng,🇰🇮
|
||||||
|
Kosovo,XK,sqi,🇽🇰
|
||||||
|
Kuwait,KW,ara,🇰🇼
|
||||||
|
Kyrgyzstan,KG,kir,🇰🇬
|
||||||
|
Laos,LA,lao,🇱🇦
|
||||||
|
Latvia,LV,lav,🇱🇻
|
||||||
|
Lebanon,LB,ara,🇱🇧
|
||||||
|
Lesotho,LS,eng,🇱🇸
|
||||||
|
Liberia,LR,eng,🇱🇷
|
||||||
|
Libya,LY,ara,🇱🇾
|
||||||
|
Liechtenstein,LI,deu,🇱🇮
|
||||||
|
Lithuania,LT,lit,🇱🇹
|
||||||
|
Luxembourg,LU,fra,🇱🇺
|
||||||
|
Macao,MO,zho,🇲🇴
|
||||||
|
Madagascar,MG,fra,🇲🇬
|
||||||
|
Malawi,MW,eng,🇲🇼
|
||||||
|
Malaysia,MY,msa,🇲🇾
|
||||||
|
Maldives,MV,div,🇲🇻
|
||||||
|
Mali,ML,fra,🇲🇱
|
||||||
|
Malta,MT,mlt,🇲🇹
|
||||||
|
Marshall Islands,MH,eng,🇲🇭
|
||||||
|
Martinique,MQ,fra,🇲🇶
|
||||||
|
Mauritania,MR,ara,🇲🇷
|
||||||
|
Mauritius,MU,eng,🇲🇺
|
||||||
|
Mayotte,YT,fra,🇾🇹
|
||||||
|
Mexico,MX,spa,🇲🇽
|
||||||
|
Micronesia,FM,eng,🇫🇲
|
||||||
|
Moldova,MD,ron,🇲🇩
|
||||||
|
Monaco,MC,fra,🇲🇨
|
||||||
|
Mongolia,MN,mon,🇲🇳
|
||||||
|
Montenegro,ME,srp,🇲🇪
|
||||||
|
Montserrat,MS,eng,🇲🇸
|
||||||
|
Morocco,MA,ara,🇲🇦
|
||||||
|
Mozambique,MZ,por,🇲🇿
|
||||||
|
Myanmar (Burma),MM,mya,🇲🇲
|
||||||
|
Namibia,NA,eng,🇳🇦
|
||||||
|
Nauru,NR,eng,🇳🇷
|
||||||
|
Nepal,NP,nep,🇳🇵
|
||||||
|
Netherlands,NL,nld,🇳🇱
|
||||||
|
New Caledonia,NC,fra,🇳🇨
|
||||||
|
New Zealand,NZ,eng,🇳🇿
|
||||||
|
Nicaragua,NI,spa,🇳🇮
|
||||||
|
Niger,NE,fra,🇳🇪
|
||||||
|
Nigeria,NG,eng,🇳🇬
|
||||||
|
Niue,NU,eng,🇳🇺
|
||||||
|
Norfolk Island,NF,eng,🇳🇫
|
||||||
|
North Korea,KP,kor,🇰🇵
|
||||||
|
North Macedonia,MK,mkd,🇲🇰
|
||||||
|
Northern Mariana Islands,MP,eng,🇲🇵
|
||||||
|
Norway,NO,nor,🇳🇴
|
||||||
|
Oman,OM,ara,🇴🇲
|
||||||
|
Pakistan,PK,eng,🇵🇰
|
||||||
|
Palau,PW,eng,🇵🇼
|
||||||
|
Palestine,PS,ara,🇵🇸
|
||||||
|
Panama,PA,spa,🇵🇦
|
||||||
|
Papua New Guinea,PG,eng,🇵🇬
|
||||||
|
Paraguay,PY,spa,🇵🇾
|
||||||
|
Peru,PE,spa,🇵🇪
|
||||||
|
Philippines,PH,eng,🇵🇭
|
||||||
|
Pitcairn Islands,PN,eng,🇵🇳
|
||||||
|
Poland,PL,pol,🇵🇱
|
||||||
|
Portugal,PT,por,🇵🇹
|
||||||
|
Puerto Rico,PR,spa,🇵🇷
|
||||||
|
Qatar,QA,ara,🇶🇦
|
||||||
|
Republic of the Congo,CG,fra,🇨🇬
|
||||||
|
Romania,RO,ron,🇷🇴
|
||||||
|
Russia,RU,rus,🇷🇺
|
||||||
|
Rwanda,RW,kin,🇷🇼
|
||||||
|
Réunion,RE,fra,🇷🇪
|
||||||
|
Saint Barthélemy,BL,fra,🇧🇱
|
||||||
|
Saint Helena,SH,eng,🇸🇭
|
||||||
|
Saint Kitts and Nevis,KN,eng,🇰🇳
|
||||||
|
Saint Lucia,LC,eng,🇱🇨
|
||||||
|
Saint Martin,MF,eng,🇲🇫
|
||||||
|
Saint Pierre and Miquelon,PM,fra,🇵🇲
|
||||||
|
Saint Vincent and the Grenadines,VC,eng,🇻🇨
|
||||||
|
Samoa,WS,smo,🇼🇸
|
||||||
|
San Marino,SM,ita,🇸🇲
|
||||||
|
Saudi Arabia,SA,ara,🇸🇦
|
||||||
|
Senegal,SN,fra,🇸🇳
|
||||||
|
Serbia,RS,srp,🇷🇸
|
||||||
|
Seychelles,SC,fra,🇸🇨
|
||||||
|
Sierra Leone,SL,eng,🇸🇱
|
||||||
|
Singapore,SG,eng,🇸🇬
|
||||||
|
Sint Maarten,SX,nld,🇸🇽
|
||||||
|
Slovakia,SK,slk,🇸🇰
|
||||||
|
Slovenia,SI,slv,🇸🇮
|
||||||
|
Solomon Islands,SB,eng,🇸🇧
|
||||||
|
Somalia,SO,som,🇸🇴
|
||||||
|
South Africa,ZA,afr,🇿🇦
|
||||||
|
South Georgia and the South Sandwich Islands,GS,eng,🇬🇸
|
||||||
|
South Korea,KR,kor,🇰🇷
|
||||||
|
South Sudan,SS,eng,🇸🇸
|
||||||
|
Spain,ES,spa,🇪🇸
|
||||||
|
Sri Lanka,LK,sin,🇱🇰
|
||||||
|
Sudan,SD,ara,🇸🇩
|
||||||
|
Suriname,SR,nld,🇸🇷
|
||||||
|
Svalbard and Jan Mayen,SJ,nor,🇸🇯
|
||||||
|
Swaziland,SZ,eng,🇸🇿
|
||||||
|
Sweden,SE,swe,🇸🇪
|
||||||
|
Switzerland,CH,deu,🇨🇭
|
||||||
|
Syria,SY,ara,🇸🇾
|
||||||
|
São Tomé and Príncipe,ST,por,🇸🇹
|
||||||
|
Taiwan,TW,zho,🇹🇼
|
||||||
|
Tajikistan,TJ,tgk,🇹🇯
|
||||||
|
Tanzania,TZ,swa,🇹🇿
|
||||||
|
Thailand,TH,tha,🇹🇭
|
||||||
|
Togo,TG,fra,🇹🇬
|
||||||
|
Tokelau,TK,eng,🇹🇰
|
||||||
|
Tonga,TO,eng,🇹🇴
|
||||||
|
Trinidad and Tobago,TT,eng,🇹🇹
|
||||||
|
Tunisia,TN,ara,🇹🇳
|
||||||
|
Turkey,TR,tur,🇹🇷
|
||||||
|
Turkmenistan,TM,tuk,🇹🇲
|
||||||
|
Turks and Caicos Islands,TC,eng,🇹🇨
|
||||||
|
Tuvalu,TV,eng,🇹🇻
|
||||||
|
U.S. Minor Outlying Islands,UM,eng,🇺🇲
|
||||||
|
U.S. Virgin Islands,VI,eng,🇻🇮
|
||||||
|
Uganda,UG,eng,🇺🇬
|
||||||
|
Ukraine,UA,ukr,🇺🇦
|
||||||
|
United Arab Emirates,AE,ara,🇦🇪
|
||||||
|
United Kingdom,UK,eng,🇬🇧
|
||||||
|
United States,US,eng,🇺🇸
|
||||||
|
Uruguay,UY,spa,🇺🇾
|
||||||
|
Uzbekistan,UZ,uzb,🇺🇿
|
||||||
|
Vanuatu,VU,bis,🇻🇺
|
||||||
|
Vatican City,VA,ita,🇻🇦
|
||||||
|
Venezuela,VE,spa,🇻🇪
|
||||||
|
Vietnam,VN,vie,🇻🇳
|
||||||
|
Wallis and Futuna,WF,fra,🇼🇫
|
||||||
|
Western Sahara,EH,spa,🇪🇭
|
||||||
|
Yemen,YE,ara,🇾🇪
|
||||||
|
Zambia,ZM,eng,🇿🇲
|
||||||
|
Zimbabwe,ZW,eng,🇿🇼
|
||||||
|
Åland,AX,swe,🇦🇽
|
|
7894
data/languages.csv
Normal file
7894
data/languages.csv
Normal file
File diff suppressed because it is too large
Load diff
25
data/regions.csv
Normal file
25
data/regions.csv
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
name,code,countries
|
||||||
|
Africa,AFR,AO;BF;BI;BJ;BW;CD;CF;CG;CI;CM;CV;DJ;DZ;EG;EH;ER;ET;GA;GH;GM;GN;GQ;GW;KE;KM;LR;LS;LY;MA;MG;ML;MR;MU;MW;MZ;NA;NE;NG;RE;RW;SC;SD;SH;SL;SN;SO;SS;ST;SZ;TD;TF;TG;TN;TZ;UG;YT;ZA;ZM;ZW
|
||||||
|
Americas,AMER,AG;AI;AR;AW;BB;BL;BM;BO;BR;BS;BV;BZ;CA;CL;CO;CR;CU;CW;DM;DO;EC;FK;GD;GF;GL;GP;GS;GT;GY;HN;HT;JM;KN;KY;LC;MF;MQ;MS;MX;NI;PA;PE;PM;PR;PY;SR;SV;SX;TC;TT;US;UY;VC;VE;VG;VI
|
||||||
|
Arab world,ARAB,AE;BH;DJ;DZ;EG;IQ;JO;KM;KW;LB;LY;MA;MR;OM;PS;QA;SA;SD;SO;SY;TN;YE
|
||||||
|
Asia,ASIA,AE;AF;AM;AZ;BD;BH;BN;BT;CN;CY;GE;ID;IL;IN;IQ;IR;JO;JP;KG;KH;KP;KR;KW;KZ;LA;LB;LK;MM;MN;MV;MY;NP;OM;PH;PK;PS;QA;RU;SA;SG;SY;TH;TJ;TL;TM;TR;TW;UZ;VN;YE
|
||||||
|
Asia-Pacific,APAC,AF;AS;AU;BD;BN;BT;CK;CN;FJ;FM;GU;ID;IN;JP;KH;KI;KP;KR;LA;LK;MH;MM;MN;MP;MV;MY;NC;NF;NP;NR;NU;NZ;PF;PG;PH;PK;PN;PW;SB;SG;TH;TK;TL;TO;TV;TW;VN;VU;WF;WS
|
||||||
|
Caribbean,CARIB,AG;AI;AW;BB;BL;BS;CU;CW;DM;DO;GD;GP;HT;JM;KN;KY;LC;MF;MQ;MS;PR;SX;TC;TT;VC;VG;VI
|
||||||
|
Central Asia,CAS,KG;KZ;TJ;TM;UZ
|
||||||
|
Commonwealth of Independent States,CIS,AM;AZ;BY;KG;KZ;MD;RU;TJ;UZ
|
||||||
|
Europe,EUR,AD;AL;AM;AT;AZ;BA;BE;BG;BY;CH;CY;CZ;DE;DK;EE;ES;FI;FR;GE;GR;HR;HU;IE;IS;IT;KZ;LI;LT;LU;LV;MC;MD;ME;MK;MT;NL;NO;PL;PT;RO;RS;RU;SE;SI;SK;SM;TR;UA;UK;VA
|
||||||
|
"Europe, the Middle East and Africa",EMEA,AD;AE;AL;AM;AO;AT;AZ;BA;BE;BF;BG;BH;BI;BJ;BW;BY;CD;CF;CG;CH;CI;CM;CV;CY;CZ;DE;DJ;DK;DZ;EE;EG;EH;ER;ES;ET;FI;FR;GA;GE;GH;GM;GN;GQ;GR;GW;HR;HU;IE;IQ;IR;IS;IT;JO;KE;KM;KW;KZ;LB;LI;LR;LS;LT;LU;LV;LY;MA;MC;MD;ME;MG;MK;ML;MR;MT;MU;MW;MZ;NA;NE;NG;NL;NO;OM;PL;PS;PT;QA;RE;RO;RS;RU;RW;SA;SC;SD;SE;SH;SI;SK;SL;SM;SN;SO;SS;ST;SY;SZ;TD;TF;TG;TN;TR;TZ;UA;UG;UK;VA;YE;YT;ZA;ZM;ZW
|
||||||
|
Hispanic America,HISPAM,AR;BO;CL;CO;CR;CU;DO;EC;GT;HN;MX;NI;PA;PE;PR;PY;SV;UY;VE
|
||||||
|
Latin America,LATAM,AR;BL;BO;BR;CL;CO;CR;CU;DO;EC;GF;GP;GT;HN;HT;MF;MQ;MX;NI;PA;PE;PR;PY;SV;UY;VE
|
||||||
|
Latin America and the Caribbean,LAC,AG;AI;AR;AW;BB;BL;BO;BR;BS;CL;CO;CR;CU;CW;DM;DO;EC;GD;GF;GP;GT;HN;HT;JM;KN;KY;LC;MF;MQ;MS;MX;NI;PA;PE;PR;PY;SV;SX;TC;TT;UY;VC;VE;VG;VI
|
||||||
|
Maghreb,MAGHREB,DZ;LY;MA;MR;TN
|
||||||
|
Middle East,MIDEAST,AE;BH;CY;EG;IL;IQ;IR;JO;KW;LB;OM;PS;QA;SA;SY;TR;YE
|
||||||
|
Middle East and North Africa,MENA,AE;BH;CY;DJ;DZ;EG;EH;IL;IQ;IR;JO;KW;LB;LY;MA;OM;PS;QA;SA;SD;SY;TN;TR;YE
|
||||||
|
Nordics,NORD,AX;DK;FO;FI;IS;NO;SE
|
||||||
|
North America,NORAM,AG;AI;AW;BB;BL;BM;BS;BZ;CA;CR;CU;CW;DM;DO;GD;GL;GP;GT;HN;HT;JM;KN;KY;LC;MF;MQ;MS;MX;NI;PA;PM;PR;SV;SX;TC;TT;US;VC;VG;VI
|
||||||
|
Northern America,NAM,BM;CA;GL;PM;US
|
||||||
|
Oceania,OCE,AS;AU;CK;FJ;FM;GU;KI;MH;MP;NC;NF;NR;NU;NZ;PF;PG;PN;PW;SB;TK;TO;TV;VU;WF;WS
|
||||||
|
South Asia,SAS,AF;BD;BT;IN;LK;MV;NP;PK
|
||||||
|
Sub-Saharan Africa,SSA,AO;BF;BI;BJ;BW;CD;CF;CG;CI;CM;CV;DJ;ER;ET;GA;GH;GM;GN;GQ;GW;KE;KM;LR;LS;MG;ML;MR;MU;MW;MZ;NA;NE;NG;RW;SC;SD;SL;SN;SO;SS;ST;SZ;TD;TG;TZ;UG;ZA;ZM;ZW
|
||||||
|
West Africa,WAFR,BF;BJ;CI;CV;GH;GM;GN;GW;LR;ML;MR;NE;NG;SH;SL;SN;TG
|
||||||
|
Worldwide,INT,AD;AE;AF;AG;AI;AL;AM;AO;AQ;AR;AS;AT;AU;AW;AX;AZ;BA;BB;BD;BE;BF;BG;BH;BI;BJ;BL;BM;BN;BO;BQ;BR;BS;BT;BV;BW;BY;BZ;CA;CC;CD;CF;CG;CH;CI;CK;CL;CM;CN;CO;CR;CU;CV;CW;CX;CY;CZ;DE;DJ;DK;DM;DO;DZ;EC;EE;EG;EH;ER;ES;ET;FI;FJ;FK;FM;FO;FR;GA;UK;GD;GE;GF;GG;GH;GI;GL;GM;GN;GP;GQ;GR;GS;GT;GU;GW;GY;HK;HM;HN;HR;HT;HU;ID;IE;IL;IM;IN;IO;IQ;IR;IS;IT;JE;JM;JO;JP;KE;KG;KH;KI;KM;KN;KP;KR;KW;KY;KZ;LA;LB;LC;LI;LK;LR;LS;LT;LU;LV;LY;MA;MC;MD;ME;MF;MG;MH;MK;ML;MM;MN;MO;MP;MQ;MR;MS;MT;MU;MV;MW;MX;MY;MZ;NA;NC;NE;NF;NG;NI;NL;NO;NP;NR;NU;NZ;OM;PA;PE;PF;PG;PH;PK;PL;PM;PN;PR;PS;PT;PW;PY;QA;RE;RO;RS;RU;RW;SA;SB;SC;SD;SE;SG;SH;SI;SJ;SK;SL;SM;SN;SO;SR;SS;ST;SV;SX;SY;SZ;TC;TD;TF;TG;TH;TJ;TK;TL;TM;TN;TO;TR;TT;TV;TW;TZ;UA;UG;UM;US;UY;UZ;VA;VC;VE;VG;VI;VN;VU;WF;WS;XK;YE;YT;ZA;ZM;ZW
|
|
3433
data/subdivisions.csv
Executable file
3433
data/subdivisions.csv
Executable file
File diff suppressed because it is too large
Load diff
1620
package-lock.json
generated
Normal file
1620
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "@iptv-org/database",
|
||||||
|
"scripts": {
|
||||||
|
"act:check": "act pull_request -W .github/workflows/check.yml",
|
||||||
|
"act:deploy": "act push -W .github/workflows/deploy.yml",
|
||||||
|
"db:validate": "node scripts/db/validate.js",
|
||||||
|
"db:export": "node scripts/db/export.js"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"author": "Arhey",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.25.0",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"cheerio": "^1.0.0-rc.10",
|
||||||
|
"commander": "^9.0.0",
|
||||||
|
"csvtojson": "^2.0.10",
|
||||||
|
"glob": "^7.2.0",
|
||||||
|
"joi": "^17.6.0",
|
||||||
|
"json2csv": "^6.0.0-alpha.0",
|
||||||
|
"mz": "^2.7.0",
|
||||||
|
"node-cleanup": "^2.1.2",
|
||||||
|
"signale": "^1.4.0",
|
||||||
|
"slugify": "^1.6.5",
|
||||||
|
"transliteration": "^2.2.0"
|
||||||
|
}
|
||||||
|
}
|
1
scripts/.gitignore
vendored
Normal file
1
scripts/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/bot.js
|
71
scripts/core/csv.js
Normal file
71
scripts/core/csv.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
const csv2json = require('csvtojson')
|
||||||
|
const fs = require('mz/fs')
|
||||||
|
const {
|
||||||
|
Parser,
|
||||||
|
transforms: { flatten },
|
||||||
|
formatters: { stringQuoteOnlyIfNecessary }
|
||||||
|
} = require('json2csv')
|
||||||
|
|
||||||
|
const csv2jsonOptions = {
|
||||||
|
checkColumn: true,
|
||||||
|
trim: true,
|
||||||
|
colParser: {
|
||||||
|
countries: listParser,
|
||||||
|
languages: listParser,
|
||||||
|
categories: listParser,
|
||||||
|
broadcast_area: listParser,
|
||||||
|
is_nsfw: boolParser,
|
||||||
|
logo: nullable,
|
||||||
|
subdivision: nullable,
|
||||||
|
city: nullable,
|
||||||
|
network: nullable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const json2csv = new Parser({
|
||||||
|
transforms: [flattenArray],
|
||||||
|
formatters: {
|
||||||
|
string: stringQuoteOnlyIfNecessary()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const csv = {}
|
||||||
|
|
||||||
|
csv.load = async function (filepath) {
|
||||||
|
return csv2json(csv2jsonOptions).fromFile(filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
csv.save = async function (filepath, data) {
|
||||||
|
const string = json2csv.parse(data)
|
||||||
|
|
||||||
|
return fs.writeFile(filepath, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
csv.saveSync = function (filepath, data) {
|
||||||
|
const string = json2csv.parse(data)
|
||||||
|
|
||||||
|
return fs.writeFileSync(filepath, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = csv
|
||||||
|
|
||||||
|
function flattenArray(item) {
|
||||||
|
for (let prop in item) {
|
||||||
|
const value = item[prop]
|
||||||
|
item[prop] = Array.isArray(value) ? value.join(';') : value
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
function listParser(value) {
|
||||||
|
return value.split(';').filter(i => i)
|
||||||
|
}
|
||||||
|
|
||||||
|
function boolParser(value) {
|
||||||
|
return value === 'true'
|
||||||
|
}
|
||||||
|
|
||||||
|
function nullable(value) {
|
||||||
|
return value === '' ? null : value
|
||||||
|
}
|
68
scripts/core/file.js
Normal file
68
scripts/core/file.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
const path = require('path')
|
||||||
|
const glob = require('glob')
|
||||||
|
const fs = require('mz/fs')
|
||||||
|
|
||||||
|
const file = {}
|
||||||
|
|
||||||
|
file.list = function (pattern) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
glob(pattern, function (err, files) {
|
||||||
|
resolve(files)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
file.getFilename = function (filepath) {
|
||||||
|
return path.parse(filepath).name
|
||||||
|
}
|
||||||
|
|
||||||
|
file.createDir = async function (dir) {
|
||||||
|
if (await file.exists(dir)) return
|
||||||
|
|
||||||
|
return fs.mkdir(dir, { recursive: true }).catch(console.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.exists = function (filepath) {
|
||||||
|
return fs.exists(path.resolve(filepath))
|
||||||
|
}
|
||||||
|
|
||||||
|
file.read = function (filepath) {
|
||||||
|
return fs.readFile(path.resolve(filepath), { encoding: 'utf8' }).catch(console.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.append = function (filepath, data) {
|
||||||
|
return fs.appendFile(path.resolve(filepath), data).catch(console.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.create = function (filepath, data = '') {
|
||||||
|
filepath = path.resolve(filepath)
|
||||||
|
const dir = path.dirname(filepath)
|
||||||
|
|
||||||
|
return file
|
||||||
|
.createDir(dir)
|
||||||
|
.then(() => file.write(filepath, data))
|
||||||
|
.catch(console.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write = function (filepath, data = '') {
|
||||||
|
return fs.writeFile(path.resolve(filepath), data, { encoding: 'utf8' }).catch(console.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.clear = async function (filepath) {
|
||||||
|
if (await file.exists(filepath)) return file.write(filepath, '')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
file.resolve = function (filepath) {
|
||||||
|
return path.resolve(filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.dirname = function (filepath) {
|
||||||
|
return path.dirname(filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.basename = function (filepath) {
|
||||||
|
return path.basename(filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = file
|
3
scripts/core/index.js
Normal file
3
scripts/core/index.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
exports.csv = require('./csv')
|
||||||
|
exports.file = require('./file')
|
||||||
|
exports.logger = require('./logger')
|
13
scripts/core/logger.js
Normal file
13
scripts/core/logger.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
const { Signale } = require('signale')
|
||||||
|
|
||||||
|
const options = {}
|
||||||
|
|
||||||
|
const logger = new Signale(options)
|
||||||
|
|
||||||
|
logger.config({
|
||||||
|
displayLabel: false,
|
||||||
|
displayScope: false,
|
||||||
|
displayBadge: false
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = logger
|
23
scripts/db/export.js
Normal file
23
scripts/db/export.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const { csv } = require('../core')
|
||||||
|
const path = require('path')
|
||||||
|
const glob = require('glob')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
const DATA_DIR = process.env.DATA_DIR || './data'
|
||||||
|
const OUTPUT_DIR = process.env.OUTPUT_DIR || './.gh-pages'
|
||||||
|
|
||||||
|
fs.exists(OUTPUT_DIR, function (exists) {
|
||||||
|
if (!exists) {
|
||||||
|
fs.mkdirSync(OUTPUT_DIR)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
glob(`${DATA_DIR}/*.csv`, async function (err, files) {
|
||||||
|
for (const inputFile of files) {
|
||||||
|
const inputFilename = path.parse(inputFile).name
|
||||||
|
const outputFile = `${OUTPUT_DIR}/${inputFilename}.json`
|
||||||
|
|
||||||
|
const json = await csv.load(inputFile)
|
||||||
|
fs.writeFileSync(path.resolve(outputFile), JSON.stringify(json))
|
||||||
|
}
|
||||||
|
})
|
10
scripts/db/schemes/categories.js
Normal file
10
scripts/db/schemes/categories.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
const Joi = require('joi')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
id: Joi.string()
|
||||||
|
.regex(/^[a-z]+$/)
|
||||||
|
.required(),
|
||||||
|
name: Joi.string()
|
||||||
|
.regex(/^[A-Z]+$/i)
|
||||||
|
.required()
|
||||||
|
}
|
27
scripts/db/schemes/channels.js
Normal file
27
scripts/db/schemes/channels.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const Joi = require('joi')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
id: Joi.string()
|
||||||
|
.regex(/^[A-Za-z0-9]+\.[a-z]{2}$/)
|
||||||
|
.required(),
|
||||||
|
name: Joi.string()
|
||||||
|
.regex(/^[\sa-zA-Z\u00C0-\u00FF0-9-!:&.+'/»#%°$@?()]+$/)
|
||||||
|
.required(),
|
||||||
|
network: Joi.string().allow(null),
|
||||||
|
country: Joi.string()
|
||||||
|
.regex(/^[A-Z]{2}$/)
|
||||||
|
.required(),
|
||||||
|
subdivision: Joi.string()
|
||||||
|
.regex(/^[A-Z]{2}-[A-Z0-9]{1,3}$/)
|
||||||
|
.allow(null),
|
||||||
|
city: Joi.string().allow(null),
|
||||||
|
broadcast_area: Joi.array().items(
|
||||||
|
Joi.string().regex(/^(s\/[A-Z]{2}-[A-Z0-9]{1,3}|c\/[A-Z]{2}|r\/[A-Z0-9]{3,7})$/)
|
||||||
|
),
|
||||||
|
languages: Joi.array()
|
||||||
|
.items(Joi.string().regex(/^[a-z]{3}$/))
|
||||||
|
.allow(''),
|
||||||
|
categories: Joi.array().items(Joi.string().regex(/^[a-z]+$/)),
|
||||||
|
is_nsfw: Joi.boolean().required(),
|
||||||
|
logo: Joi.string().uri().allow(null)
|
||||||
|
}
|
16
scripts/db/schemes/countries.js
Normal file
16
scripts/db/schemes/countries.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const Joi = require('joi')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: Joi.string()
|
||||||
|
.regex(/^[\sA-Z\u00C0-\u00FF().-]+$/i)
|
||||||
|
.required(),
|
||||||
|
code: Joi.string()
|
||||||
|
.regex(/^[A-Z]{2}$/)
|
||||||
|
.required(),
|
||||||
|
lang: Joi.string()
|
||||||
|
.regex(/^[a-z]{3}$/)
|
||||||
|
.required(),
|
||||||
|
flag: Joi.string()
|
||||||
|
.regex(/^[\uD83C][\uDDE6-\uDDFF][\uD83C][\uDDE6-\uDDFF]$/)
|
||||||
|
.required()
|
||||||
|
}
|
6
scripts/db/schemes/index.js
Normal file
6
scripts/db/schemes/index.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
exports.channels = require('./channels')
|
||||||
|
exports.categories = require('./categories')
|
||||||
|
exports.countries = require('./countries')
|
||||||
|
exports.languages = require('./languages')
|
||||||
|
exports.regions = require('./regions')
|
||||||
|
exports.subdivisions = require('./subdivisions')
|
8
scripts/db/schemes/languages.js
Normal file
8
scripts/db/schemes/languages.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
const Joi = require('joi')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
code: Joi.string()
|
||||||
|
.regex(/^[a-z]{3}$/)
|
||||||
|
.required(),
|
||||||
|
name: Joi.string().required()
|
||||||
|
}
|
15
scripts/db/schemes/regions.js
Normal file
15
scripts/db/schemes/regions.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
const Joi = require('joi')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: Joi.string()
|
||||||
|
.regex(/^[\sA-Z\u00C0-\u00FF().,-]+$/i)
|
||||||
|
.required(),
|
||||||
|
code: Joi.string()
|
||||||
|
.regex(/^[A-Z]{3,7}$/)
|
||||||
|
.required(),
|
||||||
|
countries: Joi.array().items(
|
||||||
|
Joi.string()
|
||||||
|
.regex(/^[A-Z]{2}$/)
|
||||||
|
.allow('')
|
||||||
|
)
|
||||||
|
}
|
11
scripts/db/schemes/subdivisions.js
Normal file
11
scripts/db/schemes/subdivisions.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
const Joi = require('joi')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
country: Joi.string()
|
||||||
|
.regex(/^[A-Z]{2}$/)
|
||||||
|
.required(),
|
||||||
|
name: Joi.string().required(),
|
||||||
|
code: Joi.string()
|
||||||
|
.regex(/^[A-Z]{2}-[A-Z0-9]{1,3}$/)
|
||||||
|
.required()
|
||||||
|
}
|
84
scripts/db/validate.js
Normal file
84
scripts/db/validate.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
const { logger, file, csv } = require('../core')
|
||||||
|
const { program } = require('commander')
|
||||||
|
const schemes = require('./schemes')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const Joi = require('joi')
|
||||||
|
|
||||||
|
program.argument('[filepath]', 'Path to file to validate').parse(process.argv)
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
let errors = []
|
||||||
|
const files = program.args.length
|
||||||
|
? program.args
|
||||||
|
: [
|
||||||
|
'data/categories.csv',
|
||||||
|
'data/channels.csv',
|
||||||
|
'data/countries.csv',
|
||||||
|
'data/languages.csv',
|
||||||
|
'data/regions.csv',
|
||||||
|
'data/subdivisions.csv'
|
||||||
|
]
|
||||||
|
for (const filepath of files) {
|
||||||
|
if (!filepath.endsWith('.csv')) continue
|
||||||
|
const data = await csv.load(filepath)
|
||||||
|
|
||||||
|
const filename = file.getFilename(filepath)
|
||||||
|
|
||||||
|
if (!schemes[filename]) {
|
||||||
|
logger.error(chalk.red(`\nERR: "${filename}" scheme is missing`))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileErrors = []
|
||||||
|
if (filename === 'channels') {
|
||||||
|
fileErrors = fileErrors.concat(findDuplicatesById(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = Joi.object(schemes[filename])
|
||||||
|
data.forEach((row, i) => {
|
||||||
|
const { error } = schema.validate(row, { abortEarly: false })
|
||||||
|
if (error) {
|
||||||
|
error.details.forEach(detail => {
|
||||||
|
fileErrors.push({ line: i + 2, message: detail.message })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (fileErrors.length) {
|
||||||
|
logger.info(`\n${chalk.underline(filepath)}`)
|
||||||
|
fileErrors.forEach(err => {
|
||||||
|
const position = err.line.toString().padEnd(6, ' ')
|
||||||
|
logger.error(` ${chalk.gray(position)} ${err.message}`)
|
||||||
|
})
|
||||||
|
errors = errors.concat(fileErrors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
logger.error(chalk.red(`\n${errors.length} error(s)`))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
|
function findDuplicatesById(data) {
|
||||||
|
data = data.map(i => {
|
||||||
|
i.id = i.id.toLowerCase()
|
||||||
|
return i
|
||||||
|
})
|
||||||
|
|
||||||
|
const errors = []
|
||||||
|
const schema = Joi.array().unique((a, b) => a.id === b.id)
|
||||||
|
const { error } = schema.validate(data, { abortEarly: false })
|
||||||
|
if (error) {
|
||||||
|
error.details.forEach(detail => {
|
||||||
|
errors.push({
|
||||||
|
line: detail.context.pos + 2,
|
||||||
|
message: `Entry with the id "${detail.context.value.id}" already exists`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
Loading…
Reference in a new issue