├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ ├── config.yml │ ├── need_request.yaml │ └── question_request.yaml └── workflows │ └── docker-image.yml ├── .gitignore ├── LICENSE ├── README.md ├── WechatIMG377.jpg ├── applications ├── __init__.py ├── music │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_auto_20230510_1156.py │ │ ├── 0003_folder_state.py │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── utils.py │ ├── validators.py │ └── views.py ├── subsonic │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── authentication.py │ ├── constants.py │ ├── filters.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── negotiation.py │ ├── renderers.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── task │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── constants.py │ ├── filters.py │ ├── handlers.py │ ├── management │ │ ├── __init__.py │ │ └── commands │ │ │ ├── __init__.py │ │ │ └── setup_in_docker.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_taskrecord.py │ │ ├── 0003_taskrecord_created_at.py │ │ ├── 0004_taskrecord_batch.py │ │ ├── 0005_auto_20230711_1403.py │ │ ├── 0006_auto_20230830_1458.py │ │ └── __init__.py │ ├── models.py │ ├── serialziers.py │ ├── services │ │ ├── __init__.py │ │ ├── acoust.py │ │ ├── kugou.py │ │ ├── kuwo.py │ │ ├── music_ids.py │ │ ├── music_resource.py │ │ ├── qm.py │ │ ├── scan_utils.py │ │ ├── smart_tag_resource.py │ │ └── update_ids.py │ ├── tasks.py │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── user │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_userprofile_subsonic_api_token.py │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ └── views.py └── utils │ ├── __init__.py │ ├── constant_template.py │ ├── encrypt.py │ ├── public.py │ ├── send.py │ └── translation.py ├── component ├── __init__.py ├── async_request │ ├── __init__.py │ └── aysnc_req.py ├── drf │ ├── __init__.py │ ├── adminx_expand.py │ ├── authentication.py │ ├── constants.py │ ├── filters.py │ ├── generics.py │ ├── mapping.py │ ├── middleware.py │ ├── mixins.py │ ├── pagination.py │ ├── renderers.py │ └── viewsets.py ├── music_tag │ ├── __init__.py │ ├── __main__.py │ ├── aac.py │ ├── aiff.py │ ├── apev2.py │ ├── asf.py │ ├── dsf.py │ ├── file.py │ ├── flac.py │ ├── id3.py │ ├── mp4.py │ ├── smf.py │ ├── util.py │ ├── vorbis.py │ └── wave.py ├── mysql_pool │ └── __init__.py ├── mz │ ├── __init__.py │ ├── acoustid.py │ ├── aidmatch.py │ ├── chromaprint.py │ ├── fpcalc │ ├── fpcalc.py │ ├── fpcalc_linux │ └── run.py ├── translators │ ├── __init__.py │ └── server.py ├── utils │ ├── __init__.py │ ├── basic.py │ ├── drf.py │ └── exceptions.py └── zhconv │ ├── zhcdict.json │ └── zhconv.py ├── compose ├── local │ ├── django │ │ ├── Dockerfile │ │ ├── celery │ │ │ ├── beat │ │ │ │ └── start │ │ │ └── worker │ │ │ │ └── start │ │ └── start │ └── nginx │ │ └── nginx.conf └── prod │ ├── django │ ├── Dockerfile │ ├── celery │ │ ├── beat │ │ │ └── start │ │ └── worker │ │ │ └── start │ └── start │ └── nginx │ └── nginx.conf ├── django_vue_cli ├── __init__.py ├── celery_app.py ├── settings.py ├── urls.py ├── views.py └── wsgi.py ├── images.txt ├── img.png ├── img0704.jpg ├── img_1.png ├── img_10.png ├── img_11.png ├── img_12.png ├── img_13.png ├── img_15.png ├── img_16.png ├── img_17.png ├── img_18.png ├── img_19.png ├── img_2.png ├── img_3.png ├── img_4.png ├── img_5.png ├── img_6.jpg ├── img_7.png ├── img_8.png ├── img_9.png ├── local.bak.yml ├── local.yml ├── logo.png ├── manage.py ├── music-tag.png ├── requirements.txt ├── requirements ├── base.txt └── local.txt ├── static ├── admin │ ├── css │ │ ├── autocomplete.css │ │ ├── base.css │ │ ├── changelists.css │ │ ├── dashboard.css │ │ ├── fonts.css │ │ ├── forms.css │ │ ├── login.css │ │ ├── responsive.css │ │ ├── responsive_rtl.css │ │ ├── rtl.css │ │ ├── vendor │ │ │ └── select2 │ │ │ │ ├── LICENSE-SELECT2.md │ │ │ │ ├── select2.css │ │ │ │ └── select2.min.css │ │ └── widgets.css │ ├── fonts │ │ ├── LICENSE.txt │ │ ├── README.txt │ │ ├── Roboto-Bold-webfont.woff │ │ ├── Roboto-Light-webfont.woff │ │ └── Roboto-Regular-webfont.woff │ ├── img │ │ ├── LICENSE │ │ ├── README.txt │ │ ├── calendar-icons.svg │ │ ├── gis │ │ │ ├── move_vertex_off.svg │ │ │ └── move_vertex_on.svg │ │ ├── icon-addlink.svg │ │ ├── icon-alert.svg │ │ ├── icon-calendar.svg │ │ ├── icon-changelink.svg │ │ ├── icon-clock.svg │ │ ├── icon-deletelink.svg │ │ ├── icon-no.svg │ │ ├── icon-unknown-alt.svg │ │ ├── icon-unknown.svg │ │ ├── icon-viewlink.svg │ │ ├── icon-yes.svg │ │ ├── inline-delete.svg │ │ ├── search.svg │ │ ├── selector-icons.svg │ │ ├── sorting-icons.svg │ │ ├── tooltag-add.svg │ │ └── tooltag-arrowright.svg │ └── js │ │ ├── SelectBox.js │ │ ├── SelectFilter2.js │ │ ├── actions.js │ │ ├── actions.min.js │ │ ├── admin │ │ ├── DateTimeShortcuts.js │ │ └── RelatedObjectLookups.js │ │ ├── autocomplete.js │ │ ├── calendar.js │ │ ├── cancel.js │ │ ├── change_form.js │ │ ├── collapse.js │ │ ├── collapse.min.js │ │ ├── core.js │ │ ├── inlines.js │ │ ├── inlines.min.js │ │ ├── jquery.init.js │ │ ├── popup_response.js │ │ ├── prepopulate.js │ │ ├── prepopulate.min.js │ │ ├── prepopulate_init.js │ │ ├── timeparse.js │ │ ├── urlify.js │ │ └── vendor │ │ ├── jquery │ │ ├── LICENSE.txt │ │ ├── jquery.js │ │ └── jquery.min.js │ │ ├── select2 │ │ ├── LICENSE.md │ │ ├── i18n │ │ │ ├── ar.js │ │ │ ├── az.js │ │ │ ├── bg.js │ │ │ ├── ca.js │ │ │ ├── cs.js │ │ │ ├── da.js │ │ │ ├── de.js │ │ │ ├── el.js │ │ │ ├── en.js │ │ │ ├── es.js │ │ │ ├── et.js │ │ │ ├── eu.js │ │ │ ├── fa.js │ │ │ ├── fi.js │ │ │ ├── fr.js │ │ │ ├── gl.js │ │ │ ├── he.js │ │ │ ├── hi.js │ │ │ ├── hr.js │ │ │ ├── hu.js │ │ │ ├── id.js │ │ │ ├── is.js │ │ │ ├── it.js │ │ │ ├── ja.js │ │ │ ├── km.js │ │ │ ├── ko.js │ │ │ ├── lt.js │ │ │ ├── lv.js │ │ │ ├── mk.js │ │ │ ├── ms.js │ │ │ ├── nb.js │ │ │ ├── nl.js │ │ │ ├── pl.js │ │ │ ├── pt-BR.js │ │ │ ├── pt.js │ │ │ ├── ro.js │ │ │ ├── ru.js │ │ │ ├── sk.js │ │ │ ├── sr-Cyrl.js │ │ │ ├── sr.js │ │ │ ├── sv.js │ │ │ ├── th.js │ │ │ ├── tr.js │ │ │ ├── uk.js │ │ │ ├── vi.js │ │ │ ├── zh-CN.js │ │ │ └── zh-TW.js │ │ ├── select2.full.js │ │ └── select2.full.min.js │ │ └── xregexp │ │ ├── LICENSE.txt │ │ ├── xregexp.js │ │ └── xregexp.min.js ├── dist │ ├── css │ │ └── app.css │ ├── fonts │ │ ├── fontawesome-webfont.674f50d.eot │ │ ├── fontawesome-webfont.b06871f.ttf │ │ └── fontawesome-webfont.fee66e7.woff │ ├── img │ │ ├── favicon_64.ico │ │ ├── fontawesome-webfont.912ec66.svg │ │ ├── iconcool.7d2a9d4.svg │ │ ├── music-tag.png │ │ └── music_null-cutout.png │ ├── index.prod.html │ └── js │ │ ├── app.0a49d5b848fb993c489d.js │ │ ├── manifest.9ba6c0d4f4490e9a4f28.js │ │ └── vendor.051dd49be048f27f51f9.js └── rest_framework │ ├── css │ ├── bootstrap-theme.min.css │ ├── bootstrap-tweaks.css │ ├── bootstrap.min.css │ ├── default.css │ ├── font-awesome-4.0.3.css │ └── prettify.css │ ├── docs │ ├── css │ │ ├── base.css │ │ ├── highlight.css │ │ └── jquery.json-view.min.css │ ├── img │ │ ├── favicon.ico │ │ └── grid.png │ └── js │ │ ├── api.js │ │ ├── highlight.pack.js │ │ └── jquery.json-view.min.js │ ├── fonts │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── img │ ├── glyphicons-halflings-white.png │ ├── glyphicons-halflings.png │ └── grid.png │ └── js │ ├── ajax-form.js │ ├── bootstrap.min.js │ ├── coreapi-0.1.1.js │ ├── csrf.js │ ├── default.js │ ├── jquery-3.3.1.min.js │ └── prettify-min.js ├── templates └── index.html └── web ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── .stylelintrc.js ├── README.md ├── build ├── build.js ├── check-versions.js ├── logo.png ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── debug.log ├── docs ├── install.md └── use.md ├── index.html ├── index.prod.html ├── index.template.html ├── package-lock.json ├── package.json ├── src ├── App.vue ├── api │ ├── apiUrl │ │ └── task │ │ │ └── task.js │ ├── axiosconfig │ │ ├── Interceptor.js │ │ └── axiosconfig.js │ └── index.js ├── assets │ ├── ECharts │ │ └── dataTool.min.js │ ├── base │ │ ├── css │ │ │ ├── base.scss │ │ │ ├── color.scss │ │ │ ├── headMenu.scss │ │ │ ├── leftMenu.scss │ │ │ ├── other.scss │ │ │ └── unify.scss │ │ ├── font │ │ │ └── bkicon │ │ │ │ ├── Read Me.txt │ │ │ │ ├── demo-files │ │ │ │ ├── demo.css │ │ │ │ └── demo.js │ │ │ │ ├── demo.html │ │ │ │ ├── fonts │ │ │ │ ├── icomoon.eot │ │ │ │ ├── icomoon.svg │ │ │ │ ├── icomoon.ttf │ │ │ │ └── icomoon.woff │ │ │ │ ├── selection.json │ │ │ │ └── style.css │ │ └── img │ │ │ ├── alipay.png │ │ │ ├── back_forward_16.svg │ │ │ ├── base_information_32.svg │ │ │ ├── branch_28.svg │ │ │ ├── branch_32.svg │ │ │ ├── branch_40.svg │ │ │ ├── branch_48.svg │ │ │ ├── execute.png │ │ │ ├── level1.png │ │ │ ├── level2.png │ │ │ ├── level3.png │ │ │ ├── logo-white.png │ │ │ └── wechatpay.png │ ├── custom │ │ └── css │ │ │ └── common.scss │ ├── custom_icon │ │ ├── demo.css │ │ ├── demo_index.html │ │ ├── iconfont.css │ │ ├── iconfont.js │ │ ├── iconfont.json │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── iconfont.woff2 │ └── index.js ├── common │ ├── date.js │ ├── message.js │ ├── store.js │ ├── util.js │ └── validate.js ├── components │ ├── base │ │ └── magicMenu │ │ │ ├── container.vue │ │ │ ├── header.vue │ │ │ ├── index.vue │ │ │ └── leftMenu.vue │ ├── index.js │ └── iview │ │ └── index.js ├── fiter │ ├── index.js │ └── validator │ │ └── validator.js ├── main.js ├── promission.js ├── router │ ├── _import_development.js │ ├── _import_production.js │ └── index.js ├── views │ ├── home │ │ └── home.vue │ └── user │ │ ├── index.vue │ │ └── login.vue └── vuex │ ├── actions.js │ ├── getters.js │ ├── index.js │ └── module │ └── common.js └── static ├── css └── .gitkeep ├── img ├── .gitkeep ├── favicon_64.ico ├── music-tag.png └── music_null-cutout.png └── js └── .gitkeep /.dockerignore: -------------------------------------------------------------------------------- 1 | .editorconfig 2 | .gitattributes 3 | .github 4 | .gitignore 5 | .gitlab-ci.yml 6 | .idea 7 | .pre-commit-config.yaml 8 | .readthedocs.yml 9 | .travis.yml 10 | venv 11 | .git 12 | /web/ 13 | /build/ 14 | /media/ 15 | db.sqlite3 16 | local_settings.py 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: 🐛 错误报告 | Bug Report 2 | description: 请详细描述您使用过程中遇到的问题。| Please describe in detail the problems you encountered in the process of using. 3 | title: "【Bug问题】: " 4 | labels: ["bug"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | 报告!我发现了一个了不得的 bug 10 | - type: input 11 | id: contact 12 | attributes: 13 | label: docker镜像版本 14 | description: 你当前使用的镜像版本,可在该项目系统设置-系统信息中查看。 15 | placeholder: 如:2.2.5 或 lastet(更新时间) 16 | validations: 17 | required: true 18 | - type: dropdown 19 | id: version 20 | attributes: 21 | label: MusicTagWeb 版本 22 | description: 请选择你使用的版本? 23 | options: 24 | - V1 25 | - V2 26 | default: 0 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: what-happened 31 | attributes: 32 | label: bug 描述 33 | description: 请描述你怎么遇到的 bug和出现什么现象被你认为是bug? 34 | placeholder: 请输入描述! 35 | value: "我发现..." 36 | validations: 37 | required: true 38 | - type: textarea 39 | id: logs 40 | attributes: 41 | label: 系统日志(可填) 42 | description: 请提供系统日志. 43 | render: shell 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: 📜 官方文档 | Music Tag Web Doc 3 | url: https://xiers-organization.gitbook.io/music-tag-web-v2 4 | about: 关于项目的功能用法以及设计考量,都会在官网进行呈现,提交问题之前,请先阅读官方文档,如果还不能满足,则再提问题。 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/need_request.yaml: -------------------------------------------------------------------------------- 1 | name: 🚀 功能请求 | Feature Request 2 | description: 请详细描述您期望的功能。 | Please describe in detail the features you expect. 3 | title: "【功能请求】: " 4 | labels: ["feature"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | 我有一个好的功能建议想向你提供。 10 | - type: textarea 11 | id: what-happened 12 | attributes: 13 | label: 功能描述 14 | description: 您使用的场景?您期望的结果是怎样的? 15 | placeholder: 请输入描述! 16 | value: "1.\n2.\n3" 17 | validations: 18 | required: true 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question_request.yaml: -------------------------------------------------------------------------------- 1 | name: 🙋 问题交流 | Question Report 2 | description: 在文档或讨论中没有回答的使用问题 | Usage question that isn't answered in docs or discussion 3 | title: "【问题交流】: " 4 | labels: ["question"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | 我已经仔细阅读了文档,并且没有找到答案。 10 | - type: input 11 | id: contact 12 | attributes: 13 | label: docker镜像版本 14 | description: 你当前使用的镜像版本,可在该项目系统设置-系统信息中查看。 15 | placeholder: 如:2.2.5 或 lastet(更新时间) 16 | validations: 17 | required: true 18 | - type: dropdown 19 | id: version 20 | attributes: 21 | label: MusicTagWeb 版本 22 | description: 请选择你使用的版本? 23 | options: 24 | - V1 25 | - V2 26 | default: 0 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: what-happened 31 | attributes: 32 | label: 预期行为 33 | description: 本应该这样? 34 | placeholder: 请输入描述! 35 | value: "1.\n2.\n3" 36 | validations: 37 | required: true 38 | 39 | - type: textarea 40 | id: what-happened2 41 | attributes: 42 | label: 实际行为 43 | description: 实际是怎么样? 44 | placeholder: 请输入描述! 45 | value: "1.\n2.\n3" 46 | validations: 47 | required: true 48 | - type: textarea 49 | id: what-happened3 50 | attributes: 51 | label: 原因分析(如果可以) 52 | description: 你可以尝试先分析一下原因? 53 | placeholder: 请输入描述! 54 | value: "1.\n2.\n3" 55 | validations: 56 | required: false 57 | - type: textarea 58 | id: what-happened4 59 | attributes: 60 | label: 问题重现步骤 61 | description: 你出现的问题如何重现,必要时请提供材料和截图? 62 | placeholder: 请输入描述! 63 | value: "1.\n2.\n3" 64 | validations: 65 | required: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *$py.class 4 | *.pyc 5 | .DS_Store 6 | node_modules/ 7 | /dist/ 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | # Editor directories and files 13 | .idea 14 | .vscode 15 | *.suo 16 | *.ntvs* 17 | *.njsproj 18 | *.sln 19 | local_settings.py 20 | db.sqlite3 21 | /media/ 22 | /build/ -------------------------------------------------------------------------------- /WechatIMG377.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/WechatIMG377.jpg -------------------------------------------------------------------------------- /applications/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | if os.getenv("dockerrun", "no") == "yes": 4 | from component.mysql_pool import patch_mysql 5 | from gevent import monkey 6 | monkey.patch_all(thread=False) 7 | patch_mysql() 8 | -------------------------------------------------------------------------------- /applications/music/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/music/__init__.py -------------------------------------------------------------------------------- /applications/music/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MusicConfig(AppConfig): 5 | name = 'applications.music' 6 | -------------------------------------------------------------------------------- /applications/music/migrations/0002_auto_20230510_1156.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-05-10 11:56 2 | 3 | import datetime 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('music', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='folder', 16 | name='updated_at', 17 | field=models.DateTimeField(default=datetime.datetime.now), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /applications/music/migrations/0003_folder_state.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-05-10 13:29 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('music', '0002_auto_20230510_1156'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='folder', 15 | name='state', 16 | field=models.CharField(default='none', max_length=32), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /applications/music/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/music/migrations/__init__.py -------------------------------------------------------------------------------- /applications/music/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /applications/music/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /applications/subsonic/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/subsonic/__init__.py -------------------------------------------------------------------------------- /applications/subsonic/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /applications/subsonic/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SubsonicConfig(AppConfig): 5 | name = 'subsonic' 6 | -------------------------------------------------------------------------------- /applications/subsonic/authentication.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | import hashlib 3 | 4 | from django.contrib.auth.models import User 5 | from rest_framework import authentication, exceptions 6 | from django.contrib.auth import authenticate as django_authenticate 7 | 8 | from applications.user.models import UserProfile 9 | 10 | 11 | def get_token(salt, password): 12 | to_hash = password + salt 13 | h = hashlib.md5() 14 | h.update(to_hash.encode("utf-8")) 15 | return h.hexdigest() 16 | 17 | 18 | def authenticate(username, password): 19 | try: 20 | if password.startswith("enc:"): 21 | password = password.replace("enc:", "", 1) 22 | password = binascii.unhexlify(password).decode("utf-8") 23 | 24 | user = django_authenticate(username=username, password=password) 25 | 26 | except (User.DoesNotExist, binascii.Error): 27 | raise exceptions.AuthenticationFailed("Wrong username or password.") 28 | 29 | return user, None 30 | 31 | 32 | def authenticate_salt(username, salt, token): 33 | try: 34 | user = User.objects.get(username=username) 35 | except User.DoesNotExist: 36 | raise exceptions.AuthenticationFailed("Wrong username or password.") 37 | user_profile, _ = UserProfile.objects.get_or_create(user=user) 38 | try: 39 | expected = get_token(salt, user_profile.subsonic_api_token) 40 | except Exception: 41 | raise exceptions.AuthenticationFailed("请设置你的subsonic api token") 42 | if expected != token: 43 | raise exceptions.AuthenticationFailed("Wrong username or password.") 44 | return user, None 45 | 46 | 47 | class SubsonicAuthentication(authentication.BaseAuthentication): 48 | def authenticate(self, request): 49 | data = request.GET or request.POST 50 | username = data.get("u") 51 | if not username: 52 | return None 53 | 54 | p = data.get("p") 55 | s = data.get("s") 56 | t = data.get("t") 57 | if not p and (not s or not t): 58 | raise exceptions.AuthenticationFailed("Missing credentials") 59 | 60 | if p: 61 | return authenticate(username, p) 62 | 63 | return authenticate_salt(username, s, t) 64 | -------------------------------------------------------------------------------- /applications/subsonic/constants.py: -------------------------------------------------------------------------------- 1 | AUDIO_EXTENSIONS_AND_MIMETYPE = [ 2 | # keep the most correct mimetype for each extension at the bottom 3 | ("mp3", "audio/mp3"), 4 | ("mp3", "audio/mpeg3"), 5 | ("mp3", "audio/x-mp3"), 6 | ("mp3", "audio/mpeg"), 7 | ("ogg", "video/ogg"), 8 | ("ogg", "audio/ogg"), 9 | ("opus", "audio/opus"), 10 | ("aac", "audio/x-m4a"), 11 | ("m4a", "audio/x-m4a"), 12 | ("flac", "audio/x-flac"), 13 | ("flac", "audio/flac"), 14 | ("aif", "audio/aiff"), 15 | ("aif", "audio/x-aiff"), 16 | ("aiff", "audio/aiff"), 17 | ("aiff", "audio/x-aiff"), 18 | ] 19 | COVER_TYPE = {"jpg", "jpeg", "png"} 20 | EXTENSION_TO_MIMETYPE = {ext: mt for ext, mt in AUDIO_EXTENSIONS_AND_MIMETYPE} 21 | -------------------------------------------------------------------------------- /applications/subsonic/filters.py: -------------------------------------------------------------------------------- 1 | from django_filters import rest_framework as filters 2 | 3 | from applications.music.models import Album 4 | 5 | 6 | class AlbumList2FilterSet(filters.FilterSet): 7 | type = filters.CharFilter(field_name="_", method="filter_type") 8 | 9 | class Meta: 10 | model = Album 11 | fields = [] 12 | 13 | def filter_type(self, queryset, name, value): 14 | ORDERING = { 15 | "random": "?", 16 | "newest": "-creation_date", 17 | "alphabeticalByArtist": "artist__name", 18 | "alphabeticalByName": "title", 19 | } 20 | if value not in ORDERING: 21 | return queryset 22 | 23 | return queryset.order_by(ORDERING[value]) 24 | -------------------------------------------------------------------------------- /applications/subsonic/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/subsonic/migrations/__init__.py -------------------------------------------------------------------------------- /applications/subsonic/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/subsonic/models.py -------------------------------------------------------------------------------- /applications/subsonic/negotiation.py: -------------------------------------------------------------------------------- 1 | from rest_framework import exceptions, negotiation 2 | 3 | from . import renderers 4 | 5 | MAPPING = { 6 | "json": (renderers.SubsonicJSONRenderer(), "application/json"), 7 | "xml": (renderers.SubsonicXMLRenderer(), "text/xml"), 8 | } 9 | 10 | 11 | class SubsonicContentNegociation(negotiation.DefaultContentNegotiation): 12 | def select_renderer(self, request, renderers, format_suffix=None): 13 | data = request.GET or request.POST 14 | requested_format = data.get("f", "xml") 15 | try: 16 | return MAPPING[requested_format] 17 | except KeyError: 18 | raise exceptions.NotAcceptable(available_renderers=renderers) 19 | -------------------------------------------------------------------------------- /applications/subsonic/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /applications/subsonic/urls.py: -------------------------------------------------------------------------------- 1 | from rest_framework import routers 2 | 3 | from . import views 4 | 5 | router = routers.DefaultRouter() 6 | router.register(r"", views.SubsonicViewSet, base_name='subsonic') 7 | 8 | -------------------------------------------------------------------------------- /applications/subsonic/utils.py: -------------------------------------------------------------------------------- 1 | import urllib.parse 2 | from datetime import datetime 3 | 4 | from django.conf import settings 5 | from rest_framework.response import Response 6 | 7 | from applications.subsonic.constants import EXTENSION_TO_MIMETYPE 8 | 9 | 10 | def get_type_from_ext(path): 11 | extension = path.split(".")[-1] 12 | return EXTENSION_TO_MIMETYPE.get(extension) 13 | 14 | 15 | def get_content_disposition(filename): 16 | filename = f"filename*=UTF-8''{urllib.parse.quote(filename)}" 17 | return f"attachment; {filename}" 18 | 19 | 20 | def handle_serve( 21 | track, user, _format=None, max_bitrate=None, proxy_media=True, download=False): 22 | # we update the accessed_date 23 | now = datetime.now() 24 | track.accessed_date = now 25 | track.save(update_fields=["accessed_date"]) 26 | file_path = track.path.replace(str(settings.BASE_DIR), "").encode("utf-8") 27 | mt = track.mimetype 28 | 29 | if mt: 30 | response = Response(content_type=mt) 31 | else: 32 | response = Response() 33 | mapping = {"nginx": "X-Accel-Redirect", "apache2": "X-Sendfile"} 34 | file_header = mapping[settings.REVERSE_PROXY_TYPE] 35 | response[file_header] = file_path 36 | if download: 37 | filename = track.name 38 | response["Content-Disposition"] = get_content_disposition(filename) 39 | if mt: 40 | response["Content-Type"] = mt 41 | 42 | return response 43 | -------------------------------------------------------------------------------- /applications/task/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = "applications.task.apps.ProjectConfig" 2 | -------------------------------------------------------------------------------- /applications/task/admin.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/task/admin.py -------------------------------------------------------------------------------- /applications/task/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | from django.db.models.signals import post_migrate 3 | 4 | from applications.task.handlers import init_task 5 | 6 | 7 | class ProjectConfig(AppConfig): 8 | name = 'applications.task' 9 | 10 | def ready(self): 11 | post_migrate.connect(init_task, self) 12 | -------------------------------------------------------------------------------- /applications/task/constants.py: -------------------------------------------------------------------------------- 1 | ALLOW_TYPE = ["flac", "mp3", "ape", "wav", "aiff", "wv", "tta", "m4a", "ogg", "mpc", 2 | "opus", "wma", "dsf", "dff", "wmv"] 3 | -------------------------------------------------------------------------------- /applications/task/filters.py: -------------------------------------------------------------------------------- 1 | import django_filters 2 | 3 | 4 | class TaskFilters(django_filters.FilterSet): 5 | state = django_filters.CharFilter(lookup_expr="iexact") 6 | -------------------------------------------------------------------------------- /applications/task/handlers.py: -------------------------------------------------------------------------------- 1 | def init_task(sender, **kwargs): 2 | from django.contrib.auth.models import User 3 | from applications.user.models import UserProfile 4 | import os 5 | from django.conf import settings 6 | 7 | if not User.objects.filter(username="admin").exists(): 8 | User.objects.create_superuser("admin", "admin@qq.com", "admin") 9 | 10 | UserProfile.objects.get_or_create(user=User.objects.get(username="admin")) 11 | # music_folder = os.path.join(settings.MEDIA_ROOT, "music") 12 | # os.makedirs(music_folder, exist_ok=True) 13 | -------------------------------------------------------------------------------- /applications/task/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/task/management/__init__.py -------------------------------------------------------------------------------- /applications/task/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/task/management/commands/__init__.py -------------------------------------------------------------------------------- /applications/task/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2022-09-30 16:01 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Task', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('name', models.CharField(max_length=255)), 19 | ], 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /applications/task/migrations/0002_taskrecord.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-07-11 09:35 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('task', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='TaskRecord', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('song_name', models.CharField(default='', max_length=255)), 18 | ('artist_name', models.CharField(default='', max_length=255)), 19 | ('full_path', models.CharField(default='', max_length=255)), 20 | ('tag_source', models.CharField(default='', max_length=255)), 21 | ('icon', models.CharField(default='icon-folder', max_length=255)), 22 | ('state', models.CharField(default='wait', max_length=255)), 23 | ('extra', models.TextField(default='')), 24 | ], 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /applications/task/migrations/0003_taskrecord_created_at.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-07-11 09:46 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('task', '0002_taskrecord'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='taskrecord', 15 | name='created_at', 16 | field=models.DateTimeField(auto_now_add=True, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /applications/task/migrations/0004_taskrecord_batch.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-07-11 10:43 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('task', '0003_taskrecord_created_at'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='taskrecord', 15 | name='batch', 16 | field=models.CharField(default='', max_length=255), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /applications/task/migrations/0005_auto_20230711_1403.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-07-11 14:03 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('task', '0004_taskrecord_batch'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='task', 15 | old_name='name', 16 | new_name='full_path', 17 | ), 18 | migrations.AddField( 19 | model_name='task', 20 | name='filename', 21 | field=models.CharField(default='', max_length=255), 22 | ), 23 | migrations.AddField( 24 | model_name='task', 25 | name='parent_path', 26 | field=models.CharField(default='', max_length=255), 27 | ), 28 | migrations.AddField( 29 | model_name='task', 30 | name='state', 31 | field=models.CharField(default='wait', max_length=255), 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /applications/task/migrations/0006_auto_20230830_1458.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-08-30 14:58 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('task', '0005_auto_20230711_1403'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='task', 15 | name='artist_name', 16 | field=models.CharField(default='', max_length=255), 17 | ), 18 | migrations.AddField( 19 | model_name='task', 20 | name='created_at', 21 | field=models.DateTimeField(auto_now_add=True, null=True), 22 | ), 23 | migrations.AddField( 24 | model_name='task', 25 | name='song_name', 26 | field=models.CharField(default='', max_length=255), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /applications/task/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/task/migrations/__init__.py -------------------------------------------------------------------------------- /applications/task/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Task(models.Model): 5 | song_name = models.CharField(max_length=255, default="") 6 | artist_name = models.CharField(max_length=255, default="") 7 | 8 | full_path = models.CharField(max_length=255) 9 | state = models.CharField(max_length=255, default="wait") 10 | parent_path = models.CharField(max_length=255, default="") 11 | filename = models.CharField(max_length=255, default="") 12 | created_at = models.DateTimeField(null=True, auto_now_add=True) 13 | 14 | 15 | class TaskRecord(models.Model): 16 | song_name = models.CharField(max_length=255, default="") 17 | artist_name = models.CharField(max_length=255, default="") 18 | full_path = models.CharField(max_length=255, default="") 19 | tag_source = models.CharField(max_length=255, default="") 20 | icon = models.CharField(max_length=255, default="icon-folder") 21 | state = models.CharField(max_length=255, default="wait") 22 | extra = models.TextField(default="") 23 | created_at = models.DateTimeField(null=True, auto_now_add=True) 24 | batch = models.CharField(max_length=255, default="") 25 | -------------------------------------------------------------------------------- /applications/task/services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/task/services/__init__.py -------------------------------------------------------------------------------- /applications/task/services/acoust.py: -------------------------------------------------------------------------------- 1 | from component.mz.run import get_acoustid 2 | 3 | 4 | class AcoustidClient: 5 | def fetch_id3_by_title(self, title): 6 | songs = [] 7 | res = get_acoustid(title) 8 | for each in res: 9 | songs.append({ 10 | "id": each[1], 11 | "name": each[2], 12 | "artist": each[3], 13 | "artist_id": "", 14 | "album": each[4], 15 | "album_id": "", 16 | "album_img": "", 17 | "year": "", 18 | }) 19 | return songs 20 | 21 | def fetch_lyric(self, song_id): 22 | raise Exception("暂不支持该音乐平台") 23 | -------------------------------------------------------------------------------- /applications/task/services/smart_tag_resource.py: -------------------------------------------------------------------------------- 1 | from applications.task.utils import match_score, match_artist 2 | from concurrent.futures import ThreadPoolExecutor 3 | 4 | from component import music_tag 5 | 6 | 7 | class SmartTagClient: 8 | 9 | def fetch_lyric(self, song_id): 10 | pass 11 | 12 | def run(self, resource, title): 13 | from applications.task.services.music_resource import MusicResource 14 | songs = MusicResource(resource).fetch_id3_by_title(title) 15 | for song in songs: 16 | song["resource"] = resource 17 | return songs 18 | 19 | def fetch_id3_by_title(self, info): 20 | 21 | title = info["title"] 22 | full_path = info["full_path"] 23 | file = music_tag.load_file(full_path) 24 | artist = file["artist"].value or "" 25 | album = file["album"].value or "" 26 | order_songs = [] 27 | max_score = 0 28 | with ThreadPoolExecutor(max_workers=4) as pool: 29 | results = pool.map(self.run, ["qmusic", "netease", "migu", "kugou"], [title] * 4) 30 | 31 | for songs in results: 32 | for song in songs: 33 | title_score = match_score(title, song["name"]) 34 | artist_score = match_artist(artist if artist else title, song["artist"]) 35 | album_score = match_score(album if album else title, song["album"]) 36 | if artist and artist_score == 0: 37 | artist_score = -2 38 | # 标题包含艺术家信息 39 | if not artist and artist_score >= 1: 40 | if title_score >= 1: 41 | title_score = 2 42 | song["score"] = title_score + artist_score + album_score 43 | max_score = max(max_score, song["score"]) 44 | if title_score == 0: 45 | continue 46 | order_songs.append(song) 47 | order_songs.sort(key=lambda x: x["score"], reverse=True) 48 | return order_songs[:15] 49 | -------------------------------------------------------------------------------- /applications/task/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /applications/task/urls.py: -------------------------------------------------------------------------------- 1 | from rest_framework import routers 2 | 3 | from . import views 4 | 5 | router = routers.DefaultRouter() 6 | router.register(r"", views.TaskViewSets, base_name='task') 7 | router.register(r"record", views.TaskModelViewSets, base_name='record') 8 | 9 | -------------------------------------------------------------------------------- /applications/user/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/user/__init__.py -------------------------------------------------------------------------------- /applications/user/admin.py: -------------------------------------------------------------------------------- 1 | # # -*- coding: utf-8 -*- 2 | # from django.contrib import admin 3 | # 4 | # from .models import UserProfile 5 | # 6 | # 7 | # @admin.register(UserProfile) 8 | # class UserProfileAdmin(admin.ModelAdmin): 9 | # list_display = ('id', 'user', 'subsonic_api_token') 10 | # list_filter = ('user',) 11 | -------------------------------------------------------------------------------- /applications/user/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class UserConfig(AppConfig): 5 | name = 'user' 6 | -------------------------------------------------------------------------------- /applications/user/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-04-03 10:26 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='UserProfile', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)), 22 | ], 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /applications/user/migrations/0002_userprofile_subsonic_api_token.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.6 on 2023-04-23 16:36 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('user', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='userprofile', 15 | name='subsonic_api_token', 16 | field=models.CharField(blank=True, max_length=255, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /applications/user/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/user/migrations/__init__.py -------------------------------------------------------------------------------- /applications/user/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | 5 | class UserProfile(models.Model): 6 | user = models.OneToOneField(User, related_name="profile", on_delete=models.CASCADE) 7 | subsonic_api_token = models.CharField(blank=True, null=True, max_length=255) 8 | -------------------------------------------------------------------------------- /applications/user/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /applications/user/urls.py: -------------------------------------------------------------------------------- 1 | from rest_framework import routers 2 | 3 | from . import views 4 | 5 | router = routers.DefaultRouter() 6 | router.register(r"", views.UserViewSets, base_name='user') 7 | 8 | -------------------------------------------------------------------------------- /applications/user/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework.decorators import action 2 | from rest_framework.response import Response 3 | 4 | from component.drf.viewsets import GenericViewSet 5 | 6 | 7 | class UserViewSets(GenericViewSet): 8 | @action(methods=['GET'], detail=False) 9 | def info(self, request, *args, **kwargs): 10 | return Response({ 11 | "username": request.user.username, 12 | "role": "admin" if request.user.is_superuser else "other" 13 | }) 14 | -------------------------------------------------------------------------------- /applications/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/applications/utils/__init__.py -------------------------------------------------------------------------------- /applications/utils/public.py: -------------------------------------------------------------------------------- 1 | from json import loads 2 | from django.http import HttpResponse 3 | 4 | BASE_URL = "https://music.163.com/" 5 | 6 | 7 | def readFile(method, path, mode="r"): 8 | with open(path, mode) as f: 9 | if method == "read": 10 | return f.read() 11 | elif method == "readlines": 12 | return f.readlines() 13 | 14 | 15 | def saveFile(path, content, mode="w"): 16 | with open(path, mode) as f: 17 | f.write(str(content)) 18 | 19 | 20 | def getCookie(): 21 | return loads( 22 | readFile("read", "cookies").replace("'", '"').encode() 23 | ) 24 | 25 | 26 | def request_query(r, *args): 27 | # ["id",{"ids":800435}] ["id","ids"] "id" 28 | def check(txt): 29 | if type(txt) == int: 30 | return str(txt) 31 | return txt 32 | dic = {} 33 | try: 34 | info = loads(r.body) 35 | except: 36 | pass 37 | for i in args: 38 | if type(i) == list: 39 | j = i[1] 40 | i = i[0] 41 | else: 42 | j = i 43 | if r.method == "POST": 44 | try: 45 | query = info[i] if r.body[0] == 123 else r.POST.get(i) 46 | except: 47 | query = None 48 | elif r.method == "GET": 49 | query = r.GET.get(i) 50 | try: 51 | if type(j) == dict: 52 | key = list(j.keys())[0] 53 | dic[key] = check(query if query else j[key]) 54 | else: 55 | dic[j] = check(query) 56 | except: 57 | dic[i] = check(query) 58 | return dic 59 | 60 | 61 | def Http_Response(r, text, type="application/json,charset=UTF-8"): 62 | try: 63 | query = request_query(r, "var", "cb") 64 | except: 65 | query = {"var": None, "cb": None} 66 | if query["var"] or query["cb"]: 67 | if query["var"]: 68 | text = "{}={}".format(query["var"], text) 69 | elif query["cb"]: 70 | text = "{}({})".format(query["cb"], text) 71 | type = "application/javascript; charset=UTF-8" 72 | if type == "": 73 | return HttpResponse(text) 74 | return HttpResponse(text, content_type=type) 75 | -------------------------------------------------------------------------------- /applications/utils/translation.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import random 3 | import time 4 | 5 | import requests 6 | 7 | 8 | from component import translators as ts 9 | 10 | 11 | def translation_lyc_text(contents): 12 | if len(contents) > 1000: 13 | results = [] 14 | contents = contents.split('\n') 15 | content_1k = "" 16 | for each in contents: 17 | if len(content_1k + each + '\n') > 1000: 18 | results.append(content_1k) 19 | content_1k = each + '\n' 20 | else: 21 | content_1k += each + '\n' 22 | if content_1k: 23 | results.append(content_1k) 24 | translate_res = "" 25 | for content in results: 26 | res = ts.translate_text(content, translator="youdao", to_language="zh-CHS") 27 | if translate_res: 28 | translate_res += "\n" + res 29 | else: 30 | translate_res = res 31 | return translate_res 32 | else: 33 | res = ts.translate_text(contents, translator="youdao", to_language="zh-CHS") 34 | print(res) 35 | return res 36 | 37 | -------------------------------------------------------------------------------- /component/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/component/__init__.py -------------------------------------------------------------------------------- /component/async_request/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/component/async_request/__init__.py -------------------------------------------------------------------------------- /component/drf/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /component/drf/adminx_expand.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | 4 | class MultiDBModelAdmin(admin.ModelAdmin): 5 | # A handy constant for the name of the alternate database. 6 | using = "navidrome" 7 | 8 | def save_model(self, request, obj, form, change): 9 | # Tell Django to save objects to the 'other' database. 10 | obj.save(using=self.using) 11 | 12 | def delete_model(self, request, obj): 13 | # Tell Django to delete objects from the 'other' database 14 | obj.delete(using=self.using) 15 | 16 | def get_queryset(self, request): 17 | # Tell Django to look for objects on the 'other' database. 18 | return super().get_queryset(request).using(self.using) 19 | 20 | def formfield_for_foreignkey(self, db_field, request, **kwargs): 21 | # Tell Django to populate ForeignKey widgets using a query 22 | # on the 'other' database. 23 | return super().formfield_for_foreignkey( 24 | db_field, request, using=self.using, **kwargs 25 | ) 26 | 27 | def formfield_for_manytomany(self, db_field, request, **kwargs): 28 | # Tell Django to populate ManyToMany widgets using a query 29 | # on the 'other' database. 30 | return super().formfield_for_manytomany( 31 | db_field, request, using=self.using, **kwargs 32 | ) 33 | 34 | 35 | -------------------------------------------------------------------------------- /component/drf/authentication.py: -------------------------------------------------------------------------------- 1 | from rest_framework.authentication import SessionAuthentication 2 | 3 | 4 | class CsrfExemptSessionAuthentication(SessionAuthentication): 5 | def enforce_csrf(self, request): 6 | return 7 | -------------------------------------------------------------------------------- /component/drf/constants.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from component.utils import choices_to_namedtuple, tuple_choices 4 | 5 | # 返回状态码 6 | CODE_STATUS_TUPLE = ( 7 | "OK", 8 | "UNAUTHORIZED", 9 | "VALIDATE_ERROR", 10 | "METHOD_NOT_ALLOWED", 11 | "PERMISSION_DENIED", 12 | "SERVER_500_ERROR", 13 | "OBJECT_NOT_EXIST", 14 | ) 15 | CODE_STATUS_CHOICES = tuple_choices(CODE_STATUS_TUPLE) 16 | ResponseCodeStatus = choices_to_namedtuple(CODE_STATUS_CHOICES) 17 | 18 | # 常规字段长度定义 19 | LEN_SHORT = 32 20 | LEN_NORMAL = 64 21 | LEN_MIDDLE = 128 22 | LEN_LONG = 255 23 | LEN_X_LONG = 1000 24 | LEN_XX_LONG = 10000 25 | LEN_XXX_LONG = 20000 26 | 27 | # 字段默认值 28 | EMPTY_INT = 0 29 | EMPTY_STRING = "" 30 | EMPTY_LIST = [] 31 | EMPTY_DICT = {} 32 | -------------------------------------------------------------------------------- /component/drf/filters.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from rest_framework import filters 4 | 5 | 6 | class OrderingFilter(filters.OrderingFilter): 7 | def filter_queryset(self, request, queryset, view): 8 | orderings = self.get_ordering(request, queryset, view) 9 | 10 | if orderings: 11 | custom_ordering = self.get_custom_ordering(request, view, orderings) 12 | return queryset.extra(select=custom_ordering, order_by=orderings) 13 | 14 | return queryset 15 | 16 | @staticmethod 17 | def get_ordering_class(view): 18 | return getattr(view, "ordering_class", None) 19 | 20 | def get_custom_ordering(self, request, view, orderings): 21 | custom_ordering = {} 22 | ordering_class = self.get_ordering_class(view) 23 | 24 | # viewset whether to define ordering class 25 | if ordering_class: 26 | for index, order_name in enumerate(orderings): 27 | reverse = order_name.startswith("-") 28 | order_func = getattr(ordering_class, order_name.lstrip("-"), None) 29 | 30 | # ordering class whether to define order method, Note: method name cannot be the same as field name 31 | if order_func: 32 | custom_order = order_func(reverse, request) 33 | custom_order_name = order_name.lstrip("-") 34 | custom_ordering.update({custom_order_name: custom_order}) 35 | orderings[index] = custom_order_name 36 | 37 | return custom_ordering 38 | -------------------------------------------------------------------------------- /component/drf/mapping.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from component.utils.exceptions import (AuthenticationError, NotAuthenticatedError, 3 | PermissionDeniedError, MethodNotAllowedError, 4 | NotAcceptableError, UnsupportedMediaTypeError, 5 | ThrottledError, ParamValidationError, ResourceNotFound) 6 | 7 | # drf exception to blueapps exception 8 | exception_mapping = { 9 | "ValidationError": ParamValidationError, 10 | "AuthenticationFailed": AuthenticationError, 11 | "NotAuthenticated": NotAuthenticatedError, 12 | "PermissionDenied": PermissionDeniedError, 13 | "NotFound": ResourceNotFound, 14 | "MethodNotAllowed": MethodNotAllowedError, 15 | "NotAcceptable": NotAcceptableError, 16 | "UnsupportedMediaType": UnsupportedMediaTypeError, 17 | "Throttled": ThrottledError 18 | } 19 | -------------------------------------------------------------------------------- /component/drf/pagination.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from collections import OrderedDict 3 | 4 | from rest_framework.pagination import PageNumberPagination 5 | from rest_framework.response import Response 6 | 7 | 8 | class CustomPageNumberPagination(PageNumberPagination): 9 | """ 10 | 自定义分页格式,综合页码和url 11 | """ 12 | 13 | page_size = 5 14 | page_size_query_param = "page_size" 15 | max_page_size = 10000 16 | 17 | def get_paginated_response(self, data): 18 | return Response( 19 | OrderedDict( 20 | [ 21 | ("page", self.page.number), 22 | ("total_page", self.page.paginator.num_pages), 23 | ("count", self.page.paginator.count), 24 | ("items", data), 25 | ] 26 | ) 27 | ) 28 | 29 | def get_paginated_data(self, data): 30 | return OrderedDict( 31 | [ 32 | ("page", self.page.number), 33 | ("total_page", self.page.paginator.num_pages), 34 | ("count", self.page.paginator.count), 35 | ("items", data), 36 | ] 37 | ) 38 | -------------------------------------------------------------------------------- /component/drf/renderers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 自定义drf renderers 使返回格式和ESB接口返回格式相同 4 | 使用方法: 5 | django settings 中添加 rest_framework配置 6 | REST_FRAMEWORK = { 7 | "DEFAULT_RENDERER_CLASSES": ("component.drf.renderers.CustomRenderer",), 8 | } 9 | 10 | """ 11 | from rest_framework import status 12 | from rest_framework.renderers import JSONRenderer 13 | 14 | 15 | class CustomRenderer(JSONRenderer): 16 | @staticmethod 17 | def _format_validation_message(detail): 18 | """格式化drf校验错误信息""" 19 | 20 | if isinstance(detail, list): 21 | message = "; ".join(["{}:{}".format(k, v) for k, v in enumerate(detail)]) 22 | elif isinstance(detail, dict): 23 | messages = [] 24 | for k, v in detail.items(): 25 | if isinstance(v, list): 26 | try: 27 | messages.append("{}:{}".format(k, ",".join(v))) 28 | except TypeError: 29 | messages.append("{}:{}".format(k, "部分列表元素的参数不合法,请检查")) 30 | else: 31 | messages.append("{}:{}".format(k, v)) 32 | message = ";".join(messages) 33 | else: 34 | message = detail 35 | 36 | return message 37 | 38 | def render(self, data, accepted_media_type=None, renderer_context=None): 39 | """重构render方法""" 40 | 41 | request = renderer_context.get("request") 42 | response = renderer_context.get("response") 43 | 44 | # 更改删除成功的状态码, 204 --> 200 45 | if response.status_code == status.HTTP_204_NO_CONTENT and request.method == "DELETE": 46 | response.status_code = status.HTTP_200_OK 47 | 48 | # 重新构建返回的JSON字典 49 | if response and status.is_success(response.status_code): 50 | ret = { 51 | "result": True, 52 | "code": str(response.status_code * 100), 53 | "message": "success", 54 | "data": data, 55 | } 56 | else: 57 | ret = { 58 | "result": False, 59 | "code": str((response.status_code if response else 500) * 100), 60 | "message": self._format_validation_message(detail=data.get("detail", "") or data), 61 | "data": data, 62 | } 63 | # 返回JSON数据 64 | return super(CustomRenderer, self).render(ret, accepted_media_type, renderer_context) 65 | -------------------------------------------------------------------------------- /component/music_tag/aac.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import mutagen.aac 5 | 6 | from component.music_tag.file import TAG_MAP_ENTRY 7 | from component.music_tag.apev2 import Apev2File 8 | 9 | 10 | class AacFile(Apev2File): 11 | tag_format = "AAC" 12 | mutagen_kls = mutagen.aac.AAC 13 | 14 | _TAG_MAP = Apev2File._TAG_MAP.copy() 15 | _TAG_MAP.update({ 16 | }) 17 | -------------------------------------------------------------------------------- /component/music_tag/aiff.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import mutagen.aiff 5 | 6 | from component.music_tag.file import TAG_MAP_ENTRY 7 | from component.music_tag.id3 import Id3File 8 | 9 | 10 | class AiffFile(Id3File): 11 | tag_format = "AIFF" 12 | mutagen_kls = mutagen.aiff.AIFF 13 | 14 | def __init__(self, filename, **kwargs): 15 | super(AiffFile, self).__init__(filename, **kwargs) 16 | 17 | self.tag_map = self.tag_map.copy() 18 | self.tag_map.update({ 19 | '#codec': TAG_MAP_ENTRY(getter=lambda afile, norm_key: 'aiff', 20 | type=str), 21 | '#bitspersample': TAG_MAP_ENTRY(getter='sample_size', type=int), 22 | }) 23 | -------------------------------------------------------------------------------- /component/music_tag/dsf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import mutagen.dsf 5 | 6 | from component.music_tag.file import TAG_MAP_ENTRY 7 | from component.music_tag.id3 import Id3File 8 | 9 | 10 | class DsfFile(Id3File): 11 | tag_format = "DSF" 12 | mutagen_kls = mutagen.dsf.DSF 13 | 14 | def __init__(self, filename, **kwargs): 15 | super(DsfFile, self).__init__(filename, **kwargs) 16 | 17 | self.tag_map = self.tag_map.copy() 18 | self.tag_map.update({ 19 | '#codec': TAG_MAP_ENTRY(getter=lambda afile, norm_key: 'dsf', 20 | type=str), 21 | }) 22 | -------------------------------------------------------------------------------- /component/music_tag/smf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import mutagen.smf 5 | 6 | from component.music_tag.file import AudioFile 7 | 8 | 9 | # smf: standard midi file 10 | 11 | 12 | class SmfFile(AudioFile): 13 | tag_format = "SMF" 14 | mutagen_kls = mutagen.smf.SMF 15 | 16 | def __init__(self, filename, **kwargs): 17 | raise NotImplementedError("SMF format not implemented") 18 | -------------------------------------------------------------------------------- /component/music_tag/wave.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | try: 5 | import mutagen.wave 6 | 7 | from component.music_tag.id3 import Id3File 8 | 9 | 10 | class WaveId3File(Id3File): 11 | tag_format = "Wave[Id3]" 12 | mutagen_kls = mutagen.wave.WAVE 13 | 14 | def __init__(self, filename, **kwargs): 15 | super(WaveId3File, self).__init__(filename, **kwargs) 16 | 17 | # self.tag_map = self.tag_map.copy() 18 | # self.tag_map.update({ 19 | # '#codec': TAG_MAP_ENTRY(getter=lambda afile, norm_key: 'mp3', 20 | # type=str), 21 | # '#bitspersample': TAG_MAP_ENTRY(getter=lambda afile, norm_key: None, 22 | # type=int), 23 | # }) 24 | 25 | except ImportError: 26 | pass 27 | -------------------------------------------------------------------------------- /component/mz/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/component/mz/__init__.py -------------------------------------------------------------------------------- /component/mz/fpcalc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/component/mz/fpcalc -------------------------------------------------------------------------------- /component/mz/fpcalc_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/component/mz/fpcalc_linux -------------------------------------------------------------------------------- /component/mz/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from django.conf import settings 5 | 6 | if sys.platform == 'darwin': 7 | os.environ["FPCALC"] = os.path.join(settings.BASE_DIR, "component", "mz", "fpcalc") 8 | else: 9 | os.environ["FPCALC"] = os.path.join(settings.BASE_DIR, "component", "mz", "fpcalc_linux") 10 | 11 | from component.mz import acoustid 12 | 13 | apikey = "cSpUJKpD" 14 | 15 | 16 | def get_acoustid(path): 17 | try: 18 | return acoustid.match(apikey, path) 19 | except Exception: 20 | return "" 21 | -------------------------------------------------------------------------------- /component/translators/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "5.8.0" 2 | __author__ = "UlionTse" 3 | 4 | 5 | from .server import translate_text, translate_html, translators_pool, get_languages, preaccelerate_and_speedtest 6 | -------------------------------------------------------------------------------- /component/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from .basic import * # noqa 4 | from .drf import * # noqa 5 | -------------------------------------------------------------------------------- /component/utils/basic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from collections import namedtuple 4 | 5 | 6 | def tuple_choices(tupl): 7 | """从django-model的choices转换到namedtuple""" 8 | return [(t, t) for t in tupl] 9 | 10 | 11 | def dict_to_namedtuple(dic): 12 | """从dict转换到namedtuple""" 13 | return namedtuple("AttrStore", list(dic.keys()))(**dic) 14 | 15 | 16 | def choices_to_namedtuple(choices): 17 | """从django-model的choices转换到namedtuple""" 18 | return dict_to_namedtuple(dict(choices)) 19 | -------------------------------------------------------------------------------- /component/utils/drf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | 5 | def format_validation_message(e): 6 | """格式化drf校验错误信息""" 7 | 8 | if isinstance(e.detail, list): 9 | message = "; ".join(["{}:{}".format(k, v) for k, v in enumerate(e.detail)]) 10 | elif isinstance(e.detail, dict): 11 | messages = [] 12 | for k, v in e.detail.items(): 13 | if isinstance(v, list): 14 | try: 15 | messages.append("{}:{}".format(k, ",".join(v))) 16 | except TypeError: 17 | messages.append("{}:{}".format(k, "部分列表元素的参数不合法,请检查")) 18 | else: 19 | messages.append("{}:{}".format(k, v)) 20 | message = ";".join(messages) 21 | else: 22 | message = e.detail 23 | 24 | return message 25 | -------------------------------------------------------------------------------- /compose/local/django/celery/beat/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | 7 | rm -f './celerybeat.pid' 8 | exec celery -A django_vue_cli.celery_app beat -l INFO 9 | -------------------------------------------------------------------------------- /compose/local/django/celery/worker/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | 7 | exec celery -A django_vue_cli.celery_app worker -l info -P gevent --concurrency 10 8 | -------------------------------------------------------------------------------- /compose/local/django/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | 8 | python manage.py migrate --run-syncdb 9 | gunicorn -w 2 -b 0.0.0.0:8001 django_vue_cli.wsgi:application --timeout 120 --worker-class=gevent 10 | #python manage.py runserver 0.0.0.0:8001 -------------------------------------------------------------------------------- /compose/prod/django/celery/beat/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | 7 | rm -f './celerybeat.pid' 8 | exec celery -A django_vue_cli.celery_app beat -l INFO 9 | -------------------------------------------------------------------------------- /compose/prod/django/celery/worker/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | 7 | exec celery -A django_vue_cli.celery_app worker -l info -P gevent --concurrency 10 8 | -------------------------------------------------------------------------------- /compose/prod/django/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | 8 | python manage.py migrate --run-syncdb 9 | gunicorn -w 2 -b 0.0.0.0:8001 django_vue_cli.wsgi:application --timeout 120 --worker-class=gevent 10 | #python manage.py runserver 0.0.0.0:8001 -------------------------------------------------------------------------------- /django_vue_cli/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .celery_app import app as current_app 4 | 5 | __all__ = ('current_app',) 6 | -------------------------------------------------------------------------------- /django_vue_cli/celery_app.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import absolute_import, unicode_literals 4 | 5 | import os 6 | import time 7 | from celery import Celery, platforms 8 | from django.conf import settings 9 | 10 | platforms.C_FORCE_ROOT = True 11 | 12 | # set the default Django settings module for the 'celery' program. 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_vue_cli.settings") 14 | 15 | app = Celery("django_vue_cli") 16 | 17 | # Using a string here means the worker don't have to serialize 18 | # the configuration object to child processes. 19 | # - namespace='CELERY' means all celery-related configuration keys 20 | # should have a `CELERY_` prefix. 21 | app.config_from_object("django.conf:settings") 22 | 23 | # Load task modules from all registered Django app configs. 24 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 25 | 26 | 27 | @app.task(bind=True) 28 | def debug_task(self): 29 | print("Request: {!r}".format(self.request)) 30 | time.sleep(2) 31 | -------------------------------------------------------------------------------- /django_vue_cli/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib import admin 3 | from django.urls import path, include, re_path 4 | from django_vue_cli.views import index 5 | from applications.task.urls import router as task_router 6 | from applications.user.urls import router as user_router 7 | from applications.subsonic.urls import router as subsonic_router 8 | from django.views import static 9 | from rest_framework_jwt.views import obtain_jwt_token 10 | 11 | urlpatterns = [ 12 | path('admin/', admin.site.urls), 13 | path('', index), 14 | re_path(r"^api/", include(task_router.urls)), 15 | re_path(r"^rest/", include(subsonic_router.urls)), 16 | re_path(r"^user/", include(user_router.urls)), 17 | re_path(r'^api/token/', obtain_jwt_token), 18 | # nginx 处理了静态文件 19 | re_path(r'^static/(?P<path>.*)#39;, static.serve, 20 | {'document_root': settings.STATIC_ROOT}, name='static'), 21 | re_path(r'^media/(?P<path>.*)#39;, static.serve, {'document_root': settings.MEDIA_ROOT}), 22 | ] 23 | -------------------------------------------------------------------------------- /django_vue_cli/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | 4 | def index(request): 5 | return render(request, "index.prod.html") 6 | -------------------------------------------------------------------------------- /django_vue_cli/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for task. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_vue_cli.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /images.txt: -------------------------------------------------------------------------------- 1 | xhongc/music_tag_web:latest 2 | xhongc/music_tag_web:beta 3 | --platform=linux/amd64 ubuntu:22.04 4 | --platform=linux/amd64 node:20-alpine3.20 5 | -------------------------------------------------------------------------------- /img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img.png -------------------------------------------------------------------------------- /img0704.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img0704.jpg -------------------------------------------------------------------------------- /img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_1.png -------------------------------------------------------------------------------- /img_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_10.png -------------------------------------------------------------------------------- /img_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_11.png -------------------------------------------------------------------------------- /img_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_12.png -------------------------------------------------------------------------------- /img_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_13.png -------------------------------------------------------------------------------- /img_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_15.png -------------------------------------------------------------------------------- /img_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_16.png -------------------------------------------------------------------------------- /img_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_17.png -------------------------------------------------------------------------------- /img_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_18.png -------------------------------------------------------------------------------- /img_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_19.png -------------------------------------------------------------------------------- /img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_2.png -------------------------------------------------------------------------------- /img_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_3.png -------------------------------------------------------------------------------- /img_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_4.png -------------------------------------------------------------------------------- /img_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_5.png -------------------------------------------------------------------------------- /img_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_6.jpg -------------------------------------------------------------------------------- /img_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_7.png -------------------------------------------------------------------------------- /img_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_8.png -------------------------------------------------------------------------------- /img_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/img_9.png -------------------------------------------------------------------------------- /local.bak.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | django: 5 | image: registry.cn-hangzhou.aliyuncs.com/charles0519/music_tag_web:latest 6 | container_name: music-tag-web 7 | expose: 8 | - "8001" 9 | volumes: 10 | - D:\:/app/media:z # 配置本地音乐文件夹 11 | restart: always 12 | environment: 13 | dockerrun: "yes" 14 | depends_on: 15 | - redis 16 | - db 17 | networks: 18 | - internal 19 | command: /start 20 | celeryworker: 21 | image: registry.cn-hangzhou.aliyuncs.com/charles0519/music_tag_web:latest 22 | container_name: music_celeryworker 23 | environment: 24 | dockerrun: "yes" 25 | ports: [ ] 26 | volumes: 27 | - D:\:/app/media:z # 配置本地音乐文件夹 28 | depends_on: 29 | - redis 30 | - db 31 | networks: 32 | - internal 33 | command: /start-celeryworker 34 | celerybeat: 35 | image: registry.cn-hangzhou.aliyuncs.com/charles0519/music_tag_web:latest 36 | container_name: music_celerybeat 37 | environment: 38 | dockerrun: "yes" 39 | ports: [ ] 40 | depends_on: 41 | - redis 42 | - db 43 | networks: 44 | - internal 45 | command: /start-celerybeat 46 | redis: 47 | image: redis:latest 48 | restart: always 49 | container_name: music_redis 50 | networks: 51 | - internal 52 | expose: 53 | - "6379" 54 | db: 55 | image: mysql:latest 56 | restart: always 57 | environment: 58 | MYSQL_DATABASE: music3 59 | MYSQL_ROOT_PASSWORD: 123456 60 | networks: 61 | - internal 62 | expose: 63 | - "3306" 64 | nginx: 65 | image: nginx:latest 66 | restart: always 67 | container_name: music_nginx 68 | ports: 69 | - "9150:80" 70 | networks: 71 | - internal 72 | depends_on: 73 | - django 74 | volumes: 75 | - D:\nginx.conf:/etc/nginx/nginx.conf:ro # 配置nginx.conf 76 | - D:\:/app/media:z # 配置本地音乐文件夹 77 | networks: 78 | internal: -------------------------------------------------------------------------------- /local.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | django: 5 | image: registry.cn-hangzhou.aliyuncs.com/charles0519/music_tag_web:latest 6 | container_name: music-tag-web 7 | expose: 8 | - "8001" 9 | volumes: 10 | - /Users/macbookair/Music/my_music:/app/media:z # 配置本地音乐文件夹 11 | restart: always 12 | environment: 13 | dockerrun: "yes" 14 | depends_on: 15 | - redis 16 | - db 17 | networks: 18 | - internal 19 | command: /start 20 | celeryworker: 21 | image: registry.cn-hangzhou.aliyuncs.com/charles0519/music_tag_web:latest 22 | container_name: music_celeryworker 23 | environment: 24 | dockerrun: "yes" 25 | ports: [ ] 26 | volumes: 27 | - /Users/macbookair/Music/my_music:/app/media:z # 配置本地音乐文件夹 28 | networks: 29 | - internal 30 | depends_on: 31 | - redis 32 | - db 33 | command: /start-celeryworker 34 | celerybeat: 35 | image: registry.cn-hangzhou.aliyuncs.com/charles0519/music_tag_web:latest 36 | container_name: music_celerybeat 37 | environment: 38 | dockerrun: "yes" 39 | ports: [ ] 40 | networks: 41 | - internal 42 | depends_on: 43 | - redis 44 | - db 45 | command: /start-celerybeat 46 | redis: 47 | image: redis:latest 48 | restart: always 49 | container_name: music_redis 50 | networks: 51 | - internal 52 | expose: 53 | - "6379" 54 | db: 55 | image: mysql:latest 56 | restart: always 57 | environment: 58 | MYSQL_DATABASE: music3 59 | MYSQL_ROOT_PASSWORD: 123456 60 | networks: 61 | - internal 62 | expose: 63 | - "3306" 64 | nginx: 65 | image: nginx:latest 66 | restart: always 67 | container_name: music_nginx 68 | ports: 69 | - "9150:80" 70 | networks: 71 | - internal 72 | depends_on: 73 | - django 74 | volumes: 75 | - /Users/macbookair/Music/nginx.conf:/etc/nginx/nginx.conf:ro # 配置nginx.conf 76 | - /Users/macbookair/Music/my_music:/app/media:z # 配置本地音乐文件夹 77 | networks: 78 | internal: -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/logo.png -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_vue_cli.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /music-tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/music-tag.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==2.2.6 2 | celery==4.4.7 3 | django-celery-beat==2.2.0 4 | django-celery-results==1.2.1 5 | django-cors-headers==3.2.1 6 | django-filter==2.0.0 7 | djangorestframework==3.8.1 8 | python-dateutil==2.8.2 9 | requests==2.27.1 10 | gunicorn==20.1.0 11 | gevent==21.12.0 12 | djangorestframework-jwt==1.11.0 13 | music-tag==0.4.3 14 | Pillow==9.4.0 15 | pycryptodomex==3.17 16 | Mako==1.0.6 17 | django-mysql==3.8.1 18 | -------------------------------------------------------------------------------- /requirements/base.txt: -------------------------------------------------------------------------------- 1 | Django==2.2.6 2 | celery==4.4.7 3 | django-celery-beat==2.2.0 4 | django-celery-results==1.2.1 5 | django-cors-headers==3.2.1 6 | django-filter==2.0.0 7 | djangorestframework==3.8.1 8 | python-dateutil==2.8.2 9 | requests==2.31.0 10 | gunicorn==20.1.0 11 | gevent==21.12.0 12 | djangorestframework-jwt==1.11.0 13 | music-tag==0.4.3 14 | Pillow==9.4.0 15 | pycryptodomex==3.17 16 | Mako==1.0.6 17 | django-mysql==3.8.1 18 | redis==3.2.0 19 | mysqlclient==1.4.4 20 | sqlalchemy==1.4.23 21 | PyExecJS==1.5.1 22 | tqdm==4.65.0 23 | lxml==4.9.1 24 | pathos==0.3.1 25 | -------------------------------------------------------------------------------- /requirements/local.txt: -------------------------------------------------------------------------------- 1 | -r base.txt -------------------------------------------------------------------------------- /static/admin/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* DASHBOARD */ 2 | 3 | .dashboard .module table th { 4 | width: 100%; 5 | } 6 | 7 | .dashboard .module table td { 8 | white-space: nowrap; 9 | } 10 | 11 | .dashboard .module table td a { 12 | display: block; 13 | padding-right: .6em; 14 | } 15 | 16 | /* RECENT ACTIONS MODULE */ 17 | 18 | .module ul.actionlist { 19 | margin-left: 0; 20 | } 21 | 22 | ul.actionlist li { 23 | list-style-type: none; 24 | overflow: hidden; 25 | text-overflow: ellipsis; 26 | -o-text-overflow: ellipsis; 27 | } 28 | -------------------------------------------------------------------------------- /static/admin/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | src: url('../fonts/Roboto-Bold-webfont.woff'); 4 | font-weight: 700; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'Roboto'; 10 | src: url('../fonts/Roboto-Regular-webfont.woff'); 11 | font-weight: 400; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'Roboto'; 17 | src: url('../fonts/Roboto-Light-webfont.woff'); 18 | font-weight: 300; 19 | font-style: normal; 20 | } 21 | -------------------------------------------------------------------------------- /static/admin/css/login.css: -------------------------------------------------------------------------------- 1 | /* LOGIN FORM */ 2 | 3 | body.login { 4 | background: #f8f8f8; 5 | } 6 | 7 | .login #header { 8 | height: auto; 9 | padding: 15px 16px; 10 | justify-content: center; 11 | } 12 | 13 | .login #header h1 { 14 | font-size: 18px; 15 | } 16 | 17 | .login #header h1 a { 18 | color: #fff; 19 | } 20 | 21 | .login #content { 22 | padding: 20px 20px 0; 23 | } 24 | 25 | .login #container { 26 | background: #fff; 27 | border: 1px solid #eaeaea; 28 | border-radius: 4px; 29 | overflow: hidden; 30 | width: 28em; 31 | min-width: 300px; 32 | margin: 100px auto; 33 | } 34 | 35 | .login #content-main { 36 | width: 100%; 37 | } 38 | 39 | .login .form-row { 40 | padding: 4px 0; 41 | float: left; 42 | width: 100%; 43 | border-bottom: none; 44 | } 45 | 46 | .login .form-row label { 47 | padding-right: 0.5em; 48 | line-height: 2em; 49 | font-size: 1em; 50 | clear: both; 51 | color: #333; 52 | } 53 | 54 | .login .form-row #id_username, .login .form-row #id_password { 55 | clear: both; 56 | padding: 8px; 57 | width: 100%; 58 | -webkit-box-sizing: border-box; 59 | -moz-box-sizing: border-box; 60 | box-sizing: border-box; 61 | } 62 | 63 | .login span.help { 64 | font-size: 10px; 65 | display: block; 66 | } 67 | 68 | .login .submit-row { 69 | clear: both; 70 | padding: 1em 0 0 9.4em; 71 | margin: 0; 72 | border: none; 73 | background: none; 74 | text-align: left; 75 | } 76 | 77 | .login .password-reset-link { 78 | text-align: center; 79 | } 80 | -------------------------------------------------------------------------------- /static/admin/css/responsive_rtl.css: -------------------------------------------------------------------------------- 1 | /* TABLETS */ 2 | 3 | @media (max-width: 1024px) { 4 | [dir="rtl"] .colMS { 5 | margin-right: 0; 6 | } 7 | 8 | [dir="rtl"] #user-tools { 9 | text-align: right; 10 | } 11 | 12 | [dir="rtl"] #changelist .actions label { 13 | padding-left: 10px; 14 | padding-right: 0; 15 | } 16 | 17 | [dir="rtl"] #changelist .actions select { 18 | margin-left: 0; 19 | margin-right: 15px; 20 | } 21 | 22 | [dir="rtl"] .change-list .filtered .results, 23 | [dir="rtl"] .change-list .filtered .paginator, 24 | [dir="rtl"] .filtered #toolbar, 25 | [dir="rtl"] .filtered div.xfull, 26 | [dir="rtl"] .filtered .actions { 27 | margin-right: 0; 28 | margin-left: 230px; 29 | } 30 | 31 | [dir="rtl"] .inline-group ul.tools a.add, 32 | [dir="rtl"] .inline-group div.add-row a, 33 | [dir="rtl"] .inline-group .tabular tr.add-row td a { 34 | padding: 8px 26px 8px 10px; 35 | background-position: calc(100% - 8px) 9px; 36 | } 37 | 38 | [dir="rtl"] .related-widget-wrapper-link + .selector { 39 | margin-right: 0; 40 | margin-left: 15px; 41 | } 42 | 43 | [dir="rtl"] .selector .selector-filter label { 44 | margin-right: 0; 45 | margin-left: 8px; 46 | } 47 | 48 | [dir="rtl"] .object-tools li { 49 | float: right; 50 | } 51 | 52 | [dir="rtl"] .object-tools li + li { 53 | margin-left: 0; 54 | margin-right: 15px; 55 | } 56 | 57 | [dir="rtl"] .dashboard .module table td a { 58 | padding-left: 0; 59 | padding-right: 16px; 60 | } 61 | } 62 | 63 | /* MOBILE */ 64 | 65 | @media (max-width: 767px) { 66 | [dir="rtl"] .change-list .filtered .results, 67 | [dir="rtl"] .change-list .filtered .paginator, 68 | [dir="rtl"] .filtered #toolbar, 69 | [dir="rtl"] .filtered div.xfull, 70 | [dir="rtl"] .filtered .actions { 71 | margin-left: 0; 72 | } 73 | 74 | [dir="rtl"] .aligned .add-another, 75 | [dir="rtl"] .aligned .related-lookup, 76 | [dir="rtl"] .aligned .datetimeshortcuts { 77 | margin-left: 0; 78 | margin-right: 15px; 79 | } 80 | 81 | [dir="rtl"] .aligned ul { 82 | margin-right: 0; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /static/admin/css/vendor/select2/LICENSE-SELECT2.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2015 Kevin Brown, Igor Vaynberg, and Select2 contributors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/admin/fonts/README.txt: -------------------------------------------------------------------------------- 1 | Roboto webfont source: https://www.google.com/fonts/specimen/Roboto 2 | WOFF files extracted using https://github.com/majodev/google-webfonts-helper 3 | Weights used in this project: Light (300), Regular (400), Bold (700) 4 | -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/admin/fonts/Roboto-Bold-webfont.woff -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/admin/fonts/Roboto-Light-webfont.woff -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/admin/fonts/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /static/admin/img/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Code Charm Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /static/admin/img/README.txt: -------------------------------------------------------------------------------- 1 | All icons are taken from Font Awesome (http://fontawesome.io/) project. 2 | The Font Awesome font is licensed under the SIL OFL 1.1: 3 | - https://scripts.sil.org/OFL 4 | 5 | SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG 6 | Font-Awesome-SVG-PNG is licensed under the MIT license (see file license 7 | in current folder). 8 | -------------------------------------------------------------------------------- /static/admin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | <svg width="15" height="60" viewBox="0 0 1792 7168" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <defs> 3 | <g id="previous"> 4 | <path d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 5 | </g> 6 | <g id="next"> 7 | <path d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 8 | </g> 9 | </defs> 10 | <use xlink:href="#previous" x="0" y="0" fill="#333333" /> 11 | <use xlink:href="#previous" x="0" y="1792" fill="#000000" /> 12 | <use xlink:href="#next" x="0" y="3584" fill="#333333" /> 13 | <use xlink:href="#next" x="0" y="5376" fill="#000000" /> 14 | </svg> 15 | -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_off.svg: -------------------------------------------------------------------------------- 1 | <svg width="24" height="22" viewBox="0 0 847 779" xmlns="http://www.w3.org/2000/svg"><g><path fill="#EBECE6" d="M120 1h607c66 0 120 54 120 120v536c0 66-54 120-120 120h-607c-66 0-120-54-120-120v-536c0-66 54-120 120-120z"/><path fill="#9E9E93" d="M120 1h607c66 0 120 54 120 120v536c0 66-54 120-120 120h-607c-66 0-120-54-120-120v-536c0-66 54-120 120-120zm607 25h-607c-26 0-50 11-67 28-17 18-28 41-28 67v536c0 27 11 50 28 68 17 17 41 27 67 27h607c26 0 49-10 67-27 17-18 28-41 28-68v-536c0-26-11-49-28-67-18-17-41-28-67-28z"/><path stroke="#A9A8A4" stroke-width="20" d="M706 295l-68 281"/><path stroke="#E47474" stroke-width="20" d="M316 648l390-353M141 435l175 213"/><path stroke="#C9C9C9" stroke-width="20" d="M319 151l-178 284M706 295l-387-144"/><g fill="#040405"><path d="M319 111c22 0 40 18 40 40s-18 40-40 40-40-18-40-40 18-40 40-40zM141 395c22 0 40 18 40 40s-18 40-40 40c-23 0-41-18-41-40s18-40 41-40zM316 608c22 0 40 18 40 40 0 23-18 41-40 41s-40-18-40-41c0-22 18-40 40-40zM706 254c22 0 40 18 40 41 0 22-18 40-40 40s-40-18-40-40c0-23 18-41 40-41zM638 536c22 0 40 18 40 40s-18 40-40 40-40-18-40-40 18-40 40-40z"/></g></g></svg> -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_on.svg: -------------------------------------------------------------------------------- 1 | <svg width="24" height="22" viewBox="0 0 847 779" xmlns="http://www.w3.org/2000/svg"><g><path fill="#F1C02A" d="M120 1h607c66 0 120 54 120 120v536c0 66-54 120-120 120h-607c-66 0-120-54-120-120v-536c0-66 54-120 120-120z"/><path fill="#9E9E93" d="M120 1h607c66 0 120 54 120 120v536c0 66-54 120-120 120h-607c-66 0-120-54-120-120v-536c0-66 54-120 120-120zm607 25h-607c-26 0-50 11-67 28-17 18-28 41-28 67v536c0 27 11 50 28 68 17 17 41 27 67 27h607c26 0 49-10 67-27 17-18 28-41 28-68v-536c0-26-11-49-28-67-18-17-41-28-67-28z"/><path stroke="#A9A8A4" stroke-width="20" d="M706 295l-68 281"/><path stroke="#E47474" stroke-width="20" d="M316 648l390-353M141 435l175 213"/><path stroke="#C9A741" stroke-width="20" d="M319 151l-178 284M706 295l-387-144"/><g fill="#040405"><path d="M319 111c22 0 40 18 40 40s-18 40-40 40-40-18-40-40 18-40 40-40zM141 395c22 0 40 18 40 40s-18 40-40 40c-23 0-41-18-41-40s18-40 41-40zM316 608c22 0 40 18 40 40 0 23-18 41-40 41s-40-18-40-41c0-22 18-40 40-40zM706 254c22 0 40 18 40 41 0 22-18 40-40 40s-40-18-40-40c0-23 18-41 40-41zM638 536c22 0 40 18 40 40s-18 40-40 40-40-18-40-40 18-40 40-40z"/></g></g></svg> -------------------------------------------------------------------------------- /static/admin/img/icon-addlink.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#70bf2b" d="M1600 796v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-alert.svg: -------------------------------------------------------------------------------- 1 | <svg width="14" height="14" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#efb80b" d="M1024 1375v-190q0-14-9.5-23.5t-22.5-9.5h-192q-13 0-22.5 9.5t-9.5 23.5v190q0 14 9.5 23.5t22.5 9.5h192q13 0 22.5-9.5t9.5-23.5zm-2-374l18-459q0-12-10-19-13-11-24-11h-220q-11 0-24 11-10 7-10 21l17 457q0 10 10 16.5t24 6.5h185q14 0 23.5-6.5t10.5-16.5zm-14-934l768 1408q35 63-2 126-17 29-46.5 46t-63.5 17h-1536q-34 0-63.5-17t-46.5-46q-37-63-2-126l768-1408q17-31 47-49t65-18 65 18 47 49z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | <svg width="16" height="32" viewBox="0 0 1792 3584" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <defs> 3 | <g id="icon"> 4 | <path d="M192 1664h288v-288h-288v288zm352 0h320v-288h-320v288zm-352-352h288v-320h-288v320zm352 0h320v-320h-320v320zm-352-384h288v-288h-288v288zm736 736h320v-288h-320v288zm-384-736h320v-288h-320v288zm768 736h288v-288h-288v288zm-384-352h320v-320h-320v320zm-352-864v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm736 864h288v-320h-288v320zm-384-384h320v-288h-320v288zm384 0h288v-288h-288v288zm32-480v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm384-64v1280q0 52-38 90t-90 38h-1408q-52 0-90-38t-38-90v-1280q0-52 38-90t90-38h128v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h384v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h128q52 0 90 38t38 90z"/> 5 | </g> 6 | </defs> 7 | <use xlink:href="#icon" x="0" y="0" fill="#447e9b" /> 8 | <use xlink:href="#icon" x="0" y="1792" fill="#003366" /> 9 | </svg> 10 | -------------------------------------------------------------------------------- /static/admin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#efb80b" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-clock.svg: -------------------------------------------------------------------------------- 1 | <svg width="16" height="32" viewBox="0 0 1792 3584" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <defs> 3 | <g id="icon"> 4 | <path d="M1024 544v448q0 14-9 23t-23 9h-320q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h224v-352q0-14 9-23t23-9h64q14 0 23 9t9 23zm416 352q0-148-73-273t-198-198-273-73-273 73-198 198-73 273 73 273 198 198 273 73 273-73 198-198 73-273zm224 0q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 5 | </g> 6 | </defs> 7 | <use xlink:href="#icon" x="0" y="0" fill="#447e9b" /> 8 | <use xlink:href="#icon" x="0" y="1792" fill="#003366" /> 9 | </svg> 10 | -------------------------------------------------------------------------------- /static/admin/img/icon-deletelink.svg: -------------------------------------------------------------------------------- 1 | <svg width="14" height="14" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#dd4646" d="M1490 1322q0 40-28 68l-136 136q-28 28-68 28t-68-28l-294-294-294 294q-28 28-68 28t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 294 294-294q28-28 68-28t68 28l136 136q28 28 28 68t-28 68l-294 294 294 294q28 28 28 68z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-no.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#dd4646" d="M1277 1122q0-26-19-45l-181-181 181-181q19-19 19-45 0-27-19-46l-90-90q-19-19-46-19-26 0-45 19l-181 181-181-181q-19-19-45-19-27 0-46 19l-90 90q-19 19-19 46 0 26 19 45l181 181-181 181q-19 19-19 45 0 27 19 46l90 90q19 19 46 19 26 0 45-19l181-181 181 181q19 19 45 19 27 0 46-19l90-90q19-19 19-46zm387-226q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-unknown-alt.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#ffffff" d="M1024 1376v-192q0-14-9-23t-23-9h-192q-14 0-23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23-9t9-23zm256-672q0-88-55.5-163t-138.5-116-170-41q-243 0-371 213-15 24 8 42l132 100q7 6 19 6 16 0 25-12 53-68 86-92 34-24 86-24 48 0 85.5 26t37.5 59q0 38-20 61t-68 45q-63 28-115.5 86.5t-52.5 125.5v36q0 14 9 23t23 9h192q14 0 23-9t9-23q0-19 21.5-49.5t54.5-49.5q32-18 49-28.5t46-35 44.5-48 28-60.5 12.5-81zm384 192q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-unknown.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#666666" d="M1024 1376v-192q0-14-9-23t-23-9h-192q-14 0-23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23-9t9-23zm256-672q0-88-55.5-163t-138.5-116-170-41q-243 0-371 213-15 24 8 42l132 100q7 6 19 6 16 0 25-12 53-68 86-92 34-24 86-24 48 0 85.5 26t37.5 59q0 38-20 61t-68 45q-63 28-115.5 86.5t-52.5 125.5v36q0 14 9 23t23 9h192q14 0 23-9t9-23q0-19 21.5-49.5t54.5-49.5q32-18 49-28.5t46-35 44.5-48 28-60.5 12.5-81zm384 192q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-viewlink.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#2b70bf" d="M1664 960q-152-236-381-353 61 104 61 225 0 185-131.5 316.5t-316.5 131.5-316.5-131.5-131.5-316.5q0-121 61-225-229 117-381 353 133 205 333.5 326.5t434.5 121.5 434.5-121.5 333.5-326.5zm-720-384q0-20-14-34t-34-14q-125 0-214.5 89.5t-89.5 214.5q0 20 14 34t34 14 34-14 14-34q0-86 61-147t147-61q20 0 34-14t14-34zm848 384q0 34-20 69-140 230-376.5 368.5t-499.5 138.5-499.5-139-376.5-368q-20-35-20-69t20-69q140-229 376.5-368t499.5-139 499.5 139 376.5 368q20 35 20 69z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-yes.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#70bf2b" d="M1412 734q0-28-18-46l-91-90q-19-19-45-19t-45 19l-408 407-226-226q-19-19-45-19t-45 19l-91 90q-18 18-18 46 0 27 18 45l362 362q19 19 45 19 27 0 46-19l543-543q18-18 18-45zm252 162q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/inline-delete.svg: -------------------------------------------------------------------------------- 1 | <svg width="16" height="16" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#999999" d="M1277 1122q0-26-19-45l-181-181 181-181q19-19 19-45 0-27-19-46l-90-90q-19-19-46-19-26 0-45 19l-181 181-181-181q-19-19-45-19-27 0-46 19l-90 90q-19 19-19 46 0 26 19 45l181 181-181 181q-19 19-19 45 0 27 19 46l90 90q19 19 46 19 26 0 45-19l181-181 181 181q19 19 45 19 27 0 46-19l90-90q19-19 19-46zm387-226q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/search.svg: -------------------------------------------------------------------------------- 1 | <svg width="15" height="15" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#555555" d="M1216 832q0-185-131.5-316.5t-316.5-131.5-316.5 131.5-131.5 316.5 131.5 316.5 316.5 131.5 316.5-131.5 131.5-316.5zm512 832q0 52-38 90t-90 38q-54 0-90-38l-343-342q-179 124-399 124-143 0-273.5-55.5t-225-150-150-225-55.5-273.5 55.5-273.5 150-225 225-150 273.5-55.5 273.5 55.5 225 150 150 225 55.5 273.5q0 220-124 399l343 343q37 37 37 90z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/sorting-icons.svg: -------------------------------------------------------------------------------- 1 | <svg width="14" height="84" viewBox="0 0 1792 10752" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <defs> 3 | <g id="sort"> 4 | <path d="M1408 1088q0 26-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45t19-45 45-19h896q26 0 45 19t19 45zm0-384q0 26-19 45t-45 19h-896q-26 0-45-19t-19-45 19-45l448-448q19-19 45-19t45 19l448 448q19 19 19 45z"/> 5 | </g> 6 | <g id="ascending"> 7 | <path d="M1408 1216q0 26-19 45t-45 19h-896q-26 0-45-19t-19-45 19-45l448-448q19-19 45-19t45 19l448 448q19 19 19 45z"/> 8 | </g> 9 | <g id="descending"> 10 | <path d="M1408 704q0 26-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45t19-45 45-19h896q26 0 45 19t19 45z"/> 11 | </g> 12 | </defs> 13 | <use xlink:href="#sort" x="0" y="0" fill="#999999" /> 14 | <use xlink:href="#sort" x="0" y="1792" fill="#447e9b" /> 15 | <use xlink:href="#ascending" x="0" y="3584" fill="#999999" /> 16 | <use xlink:href="#ascending" x="0" y="5376" fill="#447e9b" /> 17 | <use xlink:href="#descending" x="0" y="7168" fill="#999999" /> 18 | <use xlink:href="#descending" x="0" y="8960" fill="#447e9b" /> 19 | </svg> 20 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-add.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#ffffff" d="M1600 736v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-arrowright.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#ffffff" d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /static/admin/js/autocomplete.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | var init = function($element, options) { 4 | var settings = $.extend({ 5 | ajax: { 6 | data: function(params) { 7 | return { 8 | term: params.term, 9 | page: params.page 10 | }; 11 | } 12 | } 13 | }, options); 14 | $element.select2(settings); 15 | }; 16 | 17 | $.fn.djangoAdminSelect2 = function(options) { 18 | var settings = $.extend({}, options); 19 | $.each(this, function(i, element) { 20 | var $element = $(element); 21 | init($element, settings); 22 | }); 23 | return this; 24 | }; 25 | 26 | $(function() { 27 | // Initialize all autocomplete widgets except the one in the template 28 | // form used when a new formset is added. 29 | $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); 30 | }); 31 | 32 | $(document).on('formset:added', (function() { 33 | return function(event, $newFormset) { 34 | return $newFormset.find('.admin-autocomplete').djangoAdminSelect2(); 35 | }; 36 | })(this)); 37 | }(django.jQuery)); 38 | -------------------------------------------------------------------------------- /static/admin/js/cancel.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | $(function() { 4 | $('.cancel-link').on('click', function(e) { 5 | e.preventDefault(); 6 | if (window.location.search.indexOf('&_popup=1') === -1) { 7 | window.history.back(); // Go back if not a popup. 8 | } else { 9 | window.close(); // Otherwise, close the popup. 10 | } 11 | }); 12 | }); 13 | })(django.jQuery); 14 | -------------------------------------------------------------------------------- /static/admin/js/change_form.js: -------------------------------------------------------------------------------- 1 | /*global showAddAnotherPopup, showRelatedObjectLookupPopup showRelatedObjectPopup updateRelatedObjectLinks*/ 2 | 3 | (function($) { 4 | 'use strict'; 5 | $(document).ready(function() { 6 | var modelName = $('#django-admin-form-add-constants').data('modelName'); 7 | $('body').on('click', '.add-another', function(e) { 8 | e.preventDefault(); 9 | var event = $.Event('django:add-another-related'); 10 | $(this).trigger(event); 11 | if (!event.isDefaultPrevented()) { 12 | showAddAnotherPopup(this); 13 | } 14 | }); 15 | 16 | if (modelName) { 17 | $('form#' + modelName + '_form :input:visible:enabled:first').focus(); 18 | } 19 | }); 20 | })(django.jQuery); 21 | -------------------------------------------------------------------------------- /static/admin/js/collapse.min.js: -------------------------------------------------------------------------------- 1 | (function(){var e=function(b,a){return b.nodeName===a.toUpperCase()?b:"BODY"===b.parentNode.nodeName?null:b.parentNode&&e(b.parentNode,a)};window.addEventListener("load",function(){for(var b=document.querySelectorAll("fieldset.collapse"),a=0;a<b.length;a++){var c=b[a];if(0===c.querySelectorAll("div.errors").length){c.classList.add("collapsed");c=c.querySelector("h2");var d=document.createElement("a");d.setAttribute("id","fieldsetcollapser"+a);d.setAttribute("class","collapse-toggle");d.setAttribute("href", 2 | "#");d.textContent=gettext("Show");c.appendChild(document.createTextNode(" ("));c.appendChild(d);c.appendChild(document.createTextNode(")"))}}b=function(a){if(a.target.matches(".collapse-toggle")){a.preventDefault();a.stopPropagation();var b=e(a.target,"fieldset");b.classList.contains("collapsed")?(a.target.textContent=gettext("Hide"),b.classList.remove("collapsed")):(a.target.textContent=gettext("Show"),b.classList.add("collapsed"))}};c=document.querySelectorAll("fieldset.module");for(a=0;a<c.length;a++)c[a].addEventListener("click", 3 | b)})})(); 4 | -------------------------------------------------------------------------------- /static/admin/js/jquery.init.js: -------------------------------------------------------------------------------- 1 | /*global django:true, jQuery:false*/ 2 | /* Puts the included jQuery into our own namespace using noConflict and passing 3 | * it 'true'. This ensures that the included jQuery doesn't pollute the global 4 | * namespace (i.e. this preserves pre-existing values for both window.$ and 5 | * window.jQuery). 6 | */ 7 | var django = django || {}; 8 | django.jQuery = jQuery.noConflict(true); 9 | -------------------------------------------------------------------------------- /static/admin/js/popup_response.js: -------------------------------------------------------------------------------- 1 | /*global opener */ 2 | (function() { 3 | 'use strict'; 4 | var initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); 5 | switch(initData.action) { 6 | case 'change': 7 | opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); 8 | break; 9 | case 'delete': 10 | opener.dismissDeleteRelatedObjectPopup(window, initData.value); 11 | break; 12 | default: 13 | opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); 14 | break; 15 | } 16 | })(); 17 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate.js: -------------------------------------------------------------------------------- 1 | /*global URLify*/ 2 | (function($) { 3 | 'use strict'; 4 | $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { 5 | /* 6 | Depends on urlify.js 7 | Populates a selected field with the values of the dependent fields, 8 | URLifies and shortens the string. 9 | dependencies - array of dependent fields ids 10 | maxLength - maximum length of the URLify'd string 11 | allowUnicode - Unicode support of the URLify'd string 12 | */ 13 | return this.each(function() { 14 | var prepopulatedField = $(this); 15 | 16 | var populate = function() { 17 | // Bail if the field's value has been changed by the user 18 | if (prepopulatedField.data('_changed')) { 19 | return; 20 | } 21 | 22 | var values = []; 23 | $.each(dependencies, function(i, field) { 24 | field = $(field); 25 | if (field.val().length > 0) { 26 | values.push(field.val()); 27 | } 28 | }); 29 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); 30 | }; 31 | 32 | prepopulatedField.data('_changed', false); 33 | prepopulatedField.on('change', function() { 34 | prepopulatedField.data('_changed', true); 35 | }); 36 | 37 | if (!prepopulatedField.val()) { 38 | $(dependencies.join(',')).on('keyup change focus', populate); 39 | } 40 | }); 41 | }; 42 | })(django.jQuery); 43 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate.min.js: -------------------------------------------------------------------------------- 1 | (function(b){b.fn.prepopulate=function(d,f,g){return this.each(function(){var a=b(this),h=function(){if(!a.data("_changed")){var e=[];b.each(d,function(a,c){c=b(c);0<c.val().length&&e.push(c.val())});a.val(URLify(e.join(" "),f,g))}};a.data("_changed",!1);a.on("change",function(){a.data("_changed",!0)});if(!a.val())b(d.join(",")).on("keyup change focus",h)})}})(django.jQuery); 2 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate_init.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | var fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); 4 | $.each(fields, function(index, field) { 5 | $('.empty-form .form-row .field-' + field.name + ', .empty-form.form-row .field-' + field.name).addClass('prepopulated_field'); 6 | $(field.id).data('dependency_list', field.dependency_list).prepopulate( 7 | field.dependency_ids, field.maxLength, field.allowUnicode 8 | ); 9 | }); 10 | })(django.jQuery); 11 | -------------------------------------------------------------------------------- /static/admin/js/vendor/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | ==== 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining 10 | a copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2015 Kevin Brown, Igor Vaynberg, and Select2 contributors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ar.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="الرجاء حذف "+t+" عناصر";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="الرجاء إضافة "+t+" عناصر";return n},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(e){var t="تستطيع إختيار "+e.maximum+" بنود فقط";return t},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/az.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/az",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return t+" simvol silin"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(e){return"Sadəcə "+e.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/bg.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bg",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Моля въведете с "+t+" по-малко символ";return t>1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ca.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/cs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím zadejte o jeden znak méně":n<=4?"Prosím zadejte o "+e(n,!0)+" znaky méně":"Prosím zadejte o "+n+" znaků méně"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím zadejte ještě jeden znak":n<=4?"Prosím zadejte ještě další "+e(n,!0)+" znaky":"Prosím zadejte ještě dalších "+n+" znaků"},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky":"Můžete zvolit maximálně "+n+" položek"},noResults:function(){return"Nenalezeny žádné položky"},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/da.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Angiv venligst "+t+" tegn mindre";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Angiv venligst "+t+" tegn mere";return n},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/de.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/el.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Παρακαλώ διαγράψτε "+t+" χαρακτήρ";return t==1&&(n+="α"),t!=1&&(n+="ες"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Παρακαλώ συμπληρώστε "+t+" ή περισσότερους χαρακτήρες";return n},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(e){var t="Μπορείτε να επιλέξετε μόνο "+e.maximum+" επιλογ";return e.maximum==1&&(t+="ή"),e.maximum!=1&&(t+="ές"),t},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/en.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/es.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"La carga falló"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/et.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/eu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fa.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها میتوانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/gl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Elimine ";return t===1?n+="un carácter":n+=t+" caracteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Engada ";return t===1?n+="un carácter":n+=t+" caracteres",n},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){var t="Só pode ";return e.maximum===1?t+="un elemento":t+=e.maximum+" elementos",t},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/he.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק ";return t===1?n+="תו אחד":n+=t+" תווים",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס ";return t===1?n+="תו אחד":n+=t+" תווים",n+=" או יותר",n},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור עד ";return e.maximum===1?t+="פריט אחד":t+=e.maximum+" פריטים",t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/id.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/is.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/it.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ja.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" 文字を削除してください";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="少なくとも "+t+" 文字を入力してください";return n},loadingMore:function(){return"読み込み中…"},maximumSelected:function(e){var t=e.maximum+" 件しか選択できません";return t},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/km.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="សូមលុបចេញ "+t+" អក្សរ";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="សូមបញ្ចូល"+t+" អក្សរ រឺ ច្រើនជាងនេះ";return n},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(e){var t="អ្នកអាចជ្រើសរើសបានតែ "+e.maximum+" ជម្រើសប៉ុណ្ណោះ";return t},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ko.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/lt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%10===1&&(e%100<11||e%100>19)?t:e%10>=2&&e%10<=9&&(e%100<11||e%100>19)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"į","ius","ių"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"į","ius","ių"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ą","us","ų"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/lv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/mk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ms.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Sila hapuskan "+t+" aksara"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Sila masukkan "+t+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(e){return"Anda hanya boleh memilih "+e.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/nb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn ";return t>1?n+=" flere tegn":n+=" tegn til",n},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/nl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t=e.maximum==1?"kan":"kunnen",n="Er "+t+" maar "+e.maximum+" item";return e.maximum!=1&&(n+="s"),n+=" worden geselecteerd",n},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maximum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pt-BR.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"carácter",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ro.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return t!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți "+t+"sau mai multe caractere";return n},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",e.maximum!==1&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ru.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sr-Cyrl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr-Cyrl",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Обришите "+n+" симбол";return r+=e(n,"","а","а"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Укуцајте бар још "+n+" симбол";return r+=e(n,"","а","а"),r},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(t){var n="Можете изабрати само "+t.maximum+" ставк";return n+=e(t.maximum,"у","е","и"),n},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/th.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/tr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/uk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/vi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+' ký tự"';return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/zh-TW.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /static/admin/js/vendor/xregexp/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2007-2012 Steven Levithan <http://xregexp.com/> 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/dist/fonts/fontawesome-webfont.674f50d.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/dist/fonts/fontawesome-webfont.674f50d.eot -------------------------------------------------------------------------------- /static/dist/fonts/fontawesome-webfont.b06871f.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/dist/fonts/fontawesome-webfont.b06871f.ttf -------------------------------------------------------------------------------- /static/dist/fonts/fontawesome-webfont.fee66e7.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/dist/fonts/fontawesome-webfont.fee66e7.woff -------------------------------------------------------------------------------- /static/dist/img/favicon_64.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/dist/img/favicon_64.ico -------------------------------------------------------------------------------- /static/dist/img/music-tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/dist/img/music-tag.png -------------------------------------------------------------------------------- /static/dist/img/music_null-cutout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/dist/img/music_null-cutout.png -------------------------------------------------------------------------------- /static/dist/index.prod.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>音乐标签Web版|Music Tag Web|</title><link rel="shortcut icon" href=/static/dist/img/favicon_64.ico type=image/x-icon><link href=./static/dist/css/app.css rel=stylesheet></head><body><script>window.siteUrl = "/" 2 | window.APP_CODE = 'dj-flow'; 3 | window.CSRF_COOKIE_NAME = 'django_vue_cli_csrftoken'</script><div id=app></div><script type=text/javascript src=./static/dist/js/manifest.9ba6c0d4f4490e9a4f28.js></script><script type=text/javascript src=./static/dist/js/vendor.051dd49be048f27f51f9.js></script><script type=text/javascript src=./static/dist/js/app.0a49d5b848fb993c489d.js></script></body></html> -------------------------------------------------------------------------------- /static/dist/js/manifest.9ba6c0d4f4490e9a4f28.js: -------------------------------------------------------------------------------- 1 | !function(r){var n=window.webpackJsonp;window.webpackJsonp=function(e,u,c){for(var f,i,p,a=0,l=[];a<e.length;a++)i=e[a],o[i]&&l.push(o[i][0]),o[i]=0;for(f in u)Object.prototype.hasOwnProperty.call(u,f)&&(r[f]=u[f]);for(n&&n(e,u,c);l.length;)l.shift()();if(c)for(a=0;a<c.length;a++)p=t(t.s=c[a]);return p};var e={},o={2:0};function t(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return r[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=r,t.c=e,t.d=function(r,n,e){t.o(r,n)||Object.defineProperty(r,n,{configurable:!1,enumerable:!0,get:e})},t.n=function(r){var n=r&&r.__esModule?function(){return r.default}:function(){return r};return t.d(n,"a",n),n},t.o=function(r,n){return Object.prototype.hasOwnProperty.call(r,n)},t.p="./",t.oe=function(r){throw console.error(r),r}}([]); -------------------------------------------------------------------------------- /static/rest_framework/css/default.css: -------------------------------------------------------------------------------- 1 | /* The navbar is fixed at >= 980px wide, so add padding to the body to prevent 2 | content running up underneath it. */ 3 | 4 | h1 { 5 | font-weight: 300; 6 | } 7 | 8 | h2, h3 { 9 | font-weight: 300; 10 | } 11 | 12 | .resource-description, .response-info { 13 | margin-bottom: 2em; 14 | } 15 | 16 | .version:before { 17 | content: "v"; 18 | opacity: 0.6; 19 | padding-right: 0.25em; 20 | } 21 | 22 | .version { 23 | font-size: 70%; 24 | } 25 | 26 | .format-option { 27 | font-family: Menlo, Consolas, "Andale Mono", "Lucida Console", monospace; 28 | } 29 | 30 | .button-form { 31 | float: right; 32 | margin-right: 1em; 33 | } 34 | 35 | td.nested { 36 | padding: 0 !important; 37 | } 38 | 39 | td.nested > table { 40 | margin: 0; 41 | } 42 | 43 | form select, form input, form textarea { 44 | width: 90%; 45 | } 46 | 47 | form select[multiple] { 48 | height: 150px; 49 | } 50 | 51 | /* To allow tooltips to work on disabled elements */ 52 | .disabled-tooltip-shield { 53 | position: absolute; 54 | top: 0; 55 | right: 0; 56 | bottom: 0; 57 | left: 0; 58 | } 59 | 60 | .errorlist { 61 | margin-top: 0.5em; 62 | } 63 | 64 | pre { 65 | overflow: auto; 66 | word-wrap: normal; 67 | white-space: pre; 68 | font-size: 12px; 69 | } 70 | 71 | .page-header { 72 | border-bottom: none; 73 | padding-bottom: 0px; 74 | } 75 | 76 | #filtersModal form input[type=submit] { 77 | width: auto; 78 | } 79 | 80 | #filtersModal .modal-body h2 { 81 | margin-top: 0 82 | } 83 | -------------------------------------------------------------------------------- /static/rest_framework/css/prettify.css: -------------------------------------------------------------------------------- 1 | .com { color: #93a1a1; } 2 | .lit { color: #195f91; } 3 | .pun, .opn, .clo { color: #93a1a1; } 4 | .fun { color: #dc322f; } 5 | .str, .atv { color: #D14; } 6 | .kwd, .prettyprint .tag { color: #1e347b; } 7 | .typ, .atn, .dec, .var { color: teal; } 8 | .pln { color: #48484c; } 9 | 10 | .prettyprint { 11 | padding: 8px; 12 | background-color: #f7f7f9; 13 | border: 1px solid #e1e1e8; 14 | } 15 | .prettyprint.linenums { 16 | -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 17 | -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 18 | box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 19 | } 20 | 21 | /* Specify class=linenums on a pre to get line numbering */ 22 | ol.linenums { 23 | margin: 0 0 0 33px; /* IE indents via margin-left */ 24 | } 25 | ol.linenums li { 26 | padding-left: 12px; 27 | color: #bebec5; 28 | line-height: 20px; 29 | text-shadow: 0 1px 0 #fff; 30 | } -------------------------------------------------------------------------------- /static/rest_framework/docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | This is the GitHub theme for highlight.js 3 | 4 | github.com style (c) Vasily Polovnyov <vast@whiteants.net> 5 | 6 | */ 7 | 8 | .hljs { 9 | display: block; 10 | overflow-x: auto; 11 | padding: 0.5em; 12 | color: #333; 13 | -webkit-text-size-adjust: none; 14 | } 15 | 16 | .hljs-comment, 17 | .diff .hljs-header, 18 | .hljs-javadoc { 19 | color: #998; 20 | font-style: italic; 21 | } 22 | 23 | .hljs-keyword, 24 | .css .rule .hljs-keyword, 25 | .hljs-winutils, 26 | .nginx .hljs-title, 27 | .hljs-subst, 28 | .hljs-request, 29 | .hljs-status { 30 | color: #333; 31 | font-weight: bold; 32 | } 33 | 34 | .hljs-number, 35 | .hljs-hexcolor, 36 | .ruby .hljs-constant { 37 | color: #008080; 38 | } 39 | 40 | .hljs-string, 41 | .hljs-tag .hljs-value, 42 | .hljs-phpdoc, 43 | .hljs-dartdoc, 44 | .tex .hljs-formula { 45 | color: #d14; 46 | } 47 | 48 | .hljs-title, 49 | .hljs-id, 50 | .scss .hljs-preprocessor { 51 | color: #900; 52 | font-weight: bold; 53 | } 54 | 55 | .hljs-list .hljs-keyword, 56 | .hljs-subst { 57 | font-weight: normal; 58 | } 59 | 60 | .hljs-class .hljs-title, 61 | .hljs-type, 62 | .vhdl .hljs-literal, 63 | .tex .hljs-command { 64 | color: #458; 65 | font-weight: bold; 66 | } 67 | 68 | .hljs-tag, 69 | .hljs-tag .hljs-title, 70 | .hljs-rule .hljs-property, 71 | .django .hljs-tag .hljs-keyword { 72 | color: #000080; 73 | font-weight: normal; 74 | } 75 | 76 | .hljs-attribute, 77 | .hljs-variable, 78 | .lisp .hljs-body, 79 | .hljs-name { 80 | color: #008080; 81 | } 82 | 83 | .hljs-regexp { 84 | color: #009926; 85 | } 86 | 87 | .hljs-symbol, 88 | .ruby .hljs-symbol .hljs-string, 89 | .lisp .hljs-keyword, 90 | .clojure .hljs-keyword, 91 | .scheme .hljs-keyword, 92 | .tex .hljs-special, 93 | .hljs-prompt { 94 | color: #990073; 95 | } 96 | 97 | .hljs-built_in { 98 | color: #0086b3; 99 | } 100 | 101 | .hljs-preprocessor, 102 | .hljs-pragma, 103 | .hljs-pi, 104 | .hljs-doctype, 105 | .hljs-shebang, 106 | .hljs-cdata { 107 | color: #999; 108 | font-weight: bold; 109 | } 110 | 111 | .hljs-deletion { 112 | background: #fdd; 113 | } 114 | 115 | .hljs-addition { 116 | background: #dfd; 117 | } 118 | 119 | .diff .hljs-change { 120 | background: #0086b3; 121 | } 122 | 123 | .hljs-chunk { 124 | color: #aaa; 125 | } 126 | -------------------------------------------------------------------------------- /static/rest_framework/docs/css/jquery.json-view.min.css: -------------------------------------------------------------------------------- 1 | .json-view{position:relative} 2 | .json-view .collapser{width:20px;height:18px;display:block;position:absolute;left:-1.7em;top:-.2em;z-index:5;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D);background-repeat:no-repeat;background-position:center center;opacity:.5;cursor:pointer} 3 | .json-view .collapsed{-ms-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-khtml-transform:rotate(-90deg);-webkit-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)} 4 | .json-view .bl{display:block;padding-left:20px;margin-left:-20px;position:relative} 5 | .json-view{font-family:monospace} 6 | .json-view ul{list-style-type:none;padding-left:2em;border-left:1px dotted;margin:.3em} 7 | .json-view ul li{position:relative} 8 | .json-view .comments,.json-view .dots{display:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none} 9 | .json-view .comments{padding-left:.8em;font-style:italic;color:#888} 10 | .json-view .bool,.json-view .null,.json-view .num,.json-view .undef{font-weight:700;color:#1A01CC} 11 | .json-view .str{color:#800} -------------------------------------------------------------------------------- /static/rest_framework/docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/docs/img/favicon.ico -------------------------------------------------------------------------------- /static/rest_framework/docs/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/docs/img/grid.png -------------------------------------------------------------------------------- /static/rest_framework/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/rest_framework/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/rest_framework/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/rest_framework/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/rest_framework/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/rest_framework/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/rest_framework/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /static/rest_framework/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /static/rest_framework/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/rest_framework/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/static/rest_framework/img/grid.png -------------------------------------------------------------------------------- /static/rest_framework/js/csrf.js: -------------------------------------------------------------------------------- 1 | function getCookie(name) { 2 | var cookieValue = null; 3 | 4 | if (document.cookie && document.cookie != '') { 5 | var cookies = document.cookie.split(';'); 6 | 7 | for (var i = 0; i < cookies.length; i++) { 8 | var cookie = jQuery.trim(cookies[i]); 9 | 10 | // Does this cookie string begin with the name we want? 11 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 12 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 13 | break; 14 | } 15 | } 16 | } 17 | 18 | return cookieValue; 19 | } 20 | 21 | function csrfSafeMethod(method) { 22 | // these HTTP methods do not require CSRF protection 23 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 24 | } 25 | 26 | function sameOrigin(url) { 27 | // test that a given url is a same-origin URL 28 | // url could be relative or scheme relative or absolute 29 | var host = document.location.host; // host + port 30 | var protocol = document.location.protocol; 31 | var sr_origin = '//' + host; 32 | var origin = protocol + sr_origin; 33 | 34 | // Allow absolute or scheme relative URLs to same origin 35 | return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || 36 | (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || 37 | // or any other URL that isn't scheme relative or absolute i.e relative. 38 | !(/^(\/\/|http:|https:).*/.test(url)); 39 | } 40 | 41 | var csrftoken = getCookie(window.drf.csrfCookieName); 42 | 43 | $.ajaxSetup({ 44 | beforeSend: function(xhr, settings) { 45 | if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { 46 | // Send the token to same-origin, relative URLs only. 47 | // Send the token only if the method warrants CSRF protection 48 | // Using the CSRFToken value acquired earlier 49 | xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken); 50 | } 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /static/rest_framework/js/default.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | // JSON highlighting. 3 | prettyPrint(); 4 | 5 | // Bootstrap tooltips. 6 | $('.js-tooltip').tooltip({ 7 | delay: 1000, 8 | container: 'body' 9 | }); 10 | 11 | // Deal with rounded tab styling after tab clicks. 12 | $('a[data-toggle="tab"]:first').on('shown', function(e) { 13 | $(e.target).parents('.tabbable').addClass('first-tab-active'); 14 | }); 15 | 16 | $('a[data-toggle="tab"]:not(:first)').on('shown', function(e) { 17 | $(e.target).parents('.tabbable').removeClass('first-tab-active'); 18 | }); 19 | 20 | $('a[data-toggle="tab"]').click(function() { 21 | document.cookie = "tabstyle=" + this.name + "; path=/"; 22 | }); 23 | 24 | // Store tab preference in cookies & display appropriate tab on load. 25 | var selectedTab = null; 26 | var selectedTabName = getCookie('tabstyle'); 27 | 28 | if (selectedTabName) { 29 | selectedTabName = selectedTabName.replace(/[^a-z-]/g, ''); 30 | } 31 | 32 | if (selectedTabName) { 33 | selectedTab = $('.form-switcher a[name=' + selectedTabName + ']'); 34 | } 35 | 36 | if (selectedTab && selectedTab.length > 0) { 37 | // Display whichever tab is selected. 38 | selectedTab.tab('show'); 39 | } else { 40 | // If no tab selected, display rightmost tab. 41 | $('.form-switcher a:first').tab('show'); 42 | } 43 | 44 | $(window).load(function() { 45 | $('#errorModal').modal('show'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta name="viewport" content="width=device-width,initial-scale=1"> 6 | <title>Music Tag Web | 音乐标签 | </title> 7 | <link href="/static/dist/css/app.css" rel="stylesheet"> 8 | <link rel="shortcut icon" href="/" type="image/x-icon" /> 9 | </head> 10 | <body> 11 | <script> 12 | if ('{{ RUN_MODE }}' === 'DEVELOP') { 13 | window.siteUrl = window.location.origin 14 | } else { 15 | window.siteUrl = '{{ BK_PLAT_HOST }}{{ SITE_URL }}' 16 | } 17 | window.APP_CODE = '{{ APP_CODE }}'; 18 | window.CSRF_COOKIE_NAME = '{{ CSRF_COOKIE_NAME }}'; 19 | </script> 20 | <div id="app"></div> 21 | <script type="text/javascript" src="/static/dist/js/manifest.js"></script> 22 | <script type="text/javascript" src="/static/dist/js/vendor.js"></script> 23 | <script type="text/javascript" src="/static/dist/js/app.js"></script> 24 | </body> 25 | </html> 26 | -------------------------------------------------------------------------------- /web/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime", ["import", { 12 | "libraryName": "view-design", 13 | "libraryDirectory": "src/components" 14 | }]] 15 | } 16 | -------------------------------------------------------------------------------- /web/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /web/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /node_modules/ 6 | /src/assets/ 7 | /src/components/ 8 | /src/common/validate.js 9 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *$py.class 4 | *.pyc 5 | .DS_Store 6 | node_modules/ 7 | /dist/ 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | # Editor directories and files 13 | .idea 14 | .vscode 15 | *.suo 16 | *.ntvs* 17 | *.njsproj 18 | *.sln 19 | -------------------------------------------------------------------------------- /web/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | ## 综述 2 | * [代码目录](docs/use.md) 3 | 4 | ## 入门指南 5 | * [下载安装](docs/install.md) 6 | -------------------------------------------------------------------------------- /web/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /web/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /web/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/build/logo.png -------------------------------------------------------------------------------- /web/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /web/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"', 7 | }) 8 | -------------------------------------------------------------------------------- /web/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | } 5 | -------------------------------------------------------------------------------- /web/debug.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/debug.log -------------------------------------------------------------------------------- /web/docs/install.md: -------------------------------------------------------------------------------- 1 | 2 | ## Build Setup 3 | 4 | >建议使用淘宝镜像源 https://registry.npmjs.org 5 | 6 | ``` bash 7 | npm config set registry http://registry.npm.taobao.org 8 | ``` 9 | >查看是否切换成功 10 | 11 | 12 | ``` bash 13 | npm get registry 14 | ``` 15 | >或者使用cnpm代替npm来进行依赖安装 16 | 17 | ``` bash 18 | npm install -g cnpm --registry=https://registry.npm.taobao.org 19 | ``` 20 | 21 | ``` bash 22 | # 安装依赖 23 | npm install 24 | 25 | # 服务启动 26 | npm run dev 27 | 28 | # 生产环境build 29 | npm run build 30 | 31 | # 生产环境build以及文件分析 32 | npm run build --report 33 | ``` 34 | 35 | 如果想知道相关的[底层工作原理](http://vuejs-templates.github.io/webpack/) 和 [vue-loader 相关文档](http://vuejs.github.io/vue-loader). 36 | -------------------------------------------------------------------------------- /web/docs/use.md: -------------------------------------------------------------------------------- 1 | # 使用指南 2 | 3 | ### 主要目录结构 (src下) 4 | * src/api (后台接口) 5 | * apiUrl == 存放接口地址 6 | * axiosconfig == 接口配置 7 | * index.js == 统一引入 <br/><br/> 8 | 9 | * assets (静态文件) 10 | * base == 框架基础样式,色值,慎动!!! 11 | * custom == 自定义开发静态资源 12 | * index.js == 统一引入 <br/><br/> 13 | 14 | * component (自定义组件) 15 | * base == 框架基础组件 (头部,导航,body) 16 | * index.js == 统一挂载组件 <br/><br/> 17 | 18 | * controller (js文件,公共方法) 19 | * func == 公共方法 20 | * views == html和js分离开发,存放js文件 <br/><br/> 21 | 22 | * directive (自定义指令) 23 | * modal == 提示框指令和确认框指令 24 | * index.js == 统一挂载指令 <br/><br/> 25 | 26 | * filter (过滤器) 27 | * validator == 表单校验插件 28 | * index.js == 统一引入 <br/><br/> 29 | 30 | * router (路由存放) <br/><br/> 31 | 32 | * views (页面存放) <br/><br/> 33 | 34 | * Vuex (vuex) <br/><br/> 35 | 36 | * App.vue (入口 vue 文件) <br/><br/> 37 | 38 | * main.js (入口文件与 app.vue 相关联) 39 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <meta charset=utf-8> 5 | <meta name=viewport content="width=device-width,initial-scale=1"> 6 | <title>音乐标签Web版|Music Tag Web|</title> 7 | <link rel="shortcut icon" href="/static/dist/img/favicon_64.ico" type="image/x-icon"></link> 8 | </head> 9 | <body> 10 | <script> 11 | window.siteUrl = "http://127.0.0.1:8080/" 12 | window.APP_CODE = 'dj-flow'; 13 | window.CSRF_COOKIE_NAME = 'django_vue_cli_csrftoken' 14 | </script> 15 | <div id=app></div> 16 | </body> 17 | </html> 18 | -------------------------------------------------------------------------------- /web/index.prod.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta name="viewport" content="width=device-width,initial-scale=1"> 6 | <title>音乐标签Web版|Music Tag Web|</title> 7 | <link href="./static/dist/css/app.css" rel="stylesheet"> 8 | </head> 9 | <body> 10 | <script>window.siteUrl = 'http://127.0.0.1:8080/' 11 | window.APP_CODE = 'dj-flow' 12 | window.CSRF_COOKIE_NAME = 'django_vue_cli_csrftoken'</script> 13 | <div id="app"></div> 14 | <script type="text/javascript" src="./static/dist/js/manifest.9ba6c0d4f4490e9a4f28.js"></script> 15 | <script type="text/javascript" src="./static/dist/js/vendor.051dd49be048f27f51f9.js"></script> 16 | <script type="text/javascript" src="./static/dist/js/app.b32dfd6c67abb8b7a34f.js"></script> 17 | </body> 18 | </html> 19 | -------------------------------------------------------------------------------- /web/index.template.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <meta charset=utf-8> 5 | <meta name=viewport content="width=device-width,initial-scale=1"> 6 | <title>音乐标签Web版|Music Tag Web|</title> 7 | <link rel="shortcut icon" href="/static/dist/img/favicon_64.ico" type="image/x-icon"></link> 8 | </head> 9 | <body> 10 | <script> 11 | window.siteUrl = "/" 12 | window.APP_CODE = 'dj-flow'; 13 | window.CSRF_COOKIE_NAME = 'django_vue_cli_csrftoken' 14 | </script> 15 | <div id=app></div> 16 | </body> 17 | </html> 18 | -------------------------------------------------------------------------------- /web/src/api/apiUrl/task/task.js: -------------------------------------------------------------------------------- 1 | import {GET, POST, reUrl} from '../../axiosconfig/axiosconfig' 2 | 3 | export default { 4 | login: function(params) { 5 | return POST(reUrl + '/api/token/', params) 6 | }, 7 | loginInfo: function(params) { 8 | return GET(reUrl + '/user/info/', params) 9 | }, 10 | logout: function(params) { 11 | return POST(reUrl + '/logout/', params) 12 | }, 13 | fileList: function(params) { 14 | return POST(reUrl + '/api/file_list/', params) 15 | }, 16 | musicId3: function(params) { 17 | return POST(reUrl + '/api/music_id3/', params) 18 | }, 19 | updateId3: function(params) { 20 | return POST(reUrl + '/api/update_id3/', params) 21 | }, 22 | batchUpdateId3: function(params) { 23 | return POST(reUrl + '/api/batch_update_id3/', params) 24 | }, 25 | batchAutoUpdateId3: function(params) { 26 | return POST(reUrl + '/api/batch_auto_update_id3/', params) 27 | }, 28 | tidyFolder: function(params) { 29 | return POST(reUrl + '/api/tidy_folder/', params) 30 | }, 31 | fetchId3Title: function(params) { 32 | return POST(reUrl + '/api/fetch_id3_by_title/', params) 33 | }, 34 | fetchLyric: function(params) { 35 | return POST(reUrl + '/api/fetch_lyric/', params) 36 | }, 37 | translationLyc: function(params) { 38 | return POST(reUrl + '/api/translation_lyc/', params) 39 | }, 40 | getRecord: function(params) { 41 | return GET(reUrl + '/api/record/', params) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /web/src/api/axiosconfig/Interceptor.js: -------------------------------------------------------------------------------- 1 | // 拦截配置 2 | import Vue from 'vue' 3 | 4 | // 请求拦截 5 | export function requestFunc(request) { 6 | // if (request.config.showLoad) Vue.prototype.$showLoading(); 7 | return request 8 | } 9 | 10 | // axios 响应成功回调函数 11 | export function responseSuccessFunc(response) { 12 | // Vue.prototype.$CloseLoading(); 13 | const data = response.data.message 14 | if (data) { 15 | if (typeof (data) === 'string') { 16 | console.log(123) 17 | } else { 18 | const midstr = [] 19 | for (const i in data) { 20 | midstr.push(data[i]) 21 | } 22 | response.data.message = midstr.join(',') 23 | } 24 | } 25 | // let data = response.data.message 26 | // // if (typeof (data) == 'string') { 27 | // // } else { 28 | // try { 29 | // let midstr = [] 30 | // for (let i in data) { 31 | // midstr.push(data[i]) 32 | // } 33 | // response.data.message = midstr.join(',') 34 | // } catch { 35 | // } 36 | // } 37 | return response.data 38 | } 39 | 40 | // axios 响应失败回调函数 41 | export function responseFailFunc(error) { 42 | // Vue.prototype.$CloseLoading(); 43 | if (error.response) { 44 | switch (error.response.status) { 45 | case 404: 46 | break 47 | case 500: 48 | Vue.prototype.$Message.error('服务器错误,请联系管理员') 49 | } 50 | } else if (error.request) { 51 | if (error.code === 'ECONNABORTED') { 52 | Vue.prototype.$Message.error('远程主机拒绝网络连接') 53 | } 54 | } else { 55 | console.log(456) 56 | } 57 | return Promise.reject(error) 58 | } 59 | -------------------------------------------------------------------------------- /web/src/api/index.js: -------------------------------------------------------------------------------- 1 | // 统一引入api模块 2 | import Task from './apiUrl/task/task' 3 | 4 | export default { 5 | Task 6 | } 7 | -------------------------------------------------------------------------------- /web/src/assets/base/css/base.scss: -------------------------------------------------------------------------------- 1 | // 基础样式 2 | html { 3 | //height: 100%; 4 | } 5 | 6 | body { 7 | height: 100%; 8 | margin: 0; 9 | padding: 0; 10 | font-size: 13px; 11 | } 12 | 13 | body a { 14 | text-decoration: none; 15 | } 16 | 17 | body a:hover { 18 | cursor: pointer; 19 | } 20 | 21 | body ul { 22 | margin: 0; 23 | padding: 0; 24 | list-style: none; 25 | } 26 | 27 | 28 | /*全局滚动条样式*/ 29 | ::-webkit-scrollbar { 30 | width: 6px; 31 | } 32 | 33 | ::-webkit-scrollbar-thumb { //滑块部分 34 | /* background-color: #01c8dc; 35 | border-radius: 3px; */ 36 | background-color: #c4c6cc; 37 | } 38 | ::-webkit-scrollbar-track { //轨道部分 39 | // background: #ededed; 40 | border-radius: 5px; 41 | } 42 | 43 | #app { 44 | font-family: PingFang SC, Microsoft Yahei; 45 | -webkit-font-smoothing: antialiased; 46 | -moz-osx-font-smoothing: grayscale; 47 | //min-width: 1280px; 48 | overflow-y: hidden; 49 | width: 100%; 50 | position: relative; 51 | height: 100%; 52 | } 53 | -------------------------------------------------------------------------------- /web/src/assets/base/css/color.scss: -------------------------------------------------------------------------------- 1 | // 基础颜色统一配置 2 | $head-theme: 'light'; //选择 light 或 blue 3 | $headerHeight: 60px; 4 | 5 | $base-color: #217FC3; //导航主⾊ 导航⽂字 重要按钮 链接⽂本 6 | $base-hover: #446DB3; //主色hover 7 | 8 | $base-color-blue: #BFE3EB; //蓝色主题的导航主⾊ 导航⽂字 重要按钮 链接⽂本 9 | 10 | $primary-color: #3EC8FF; //次要按钮 11 | $primary-hover: #44B3E0; //hover 12 | 13 | $success-color: #5BD18B; //操作成功 谨慎使⽤ 成功信息 14 | $success-hover: #4CAA72; //hover 15 | 16 | $warn-color: #FEA30D; //警告,谨慎使用 17 | $warn-hover: #Ec9300; //hover 18 | 19 | $error-color: #ED3F3F; //操作警告 信息提醒 失败信息 20 | $error-hover: #Dd2424; //hover 21 | 22 | $cancel-color: #C9C9C9; //取消选择 边框颜⾊ 23 | $cancel-hover: #A9A9A9; //hover 24 | 25 | $nav-color: #90BFE1; //导航hover 26 | 27 | $sup-color: #F4F9FA; //辅色 28 | 29 | $dis-color: #EEE; //禁用按钮 弱分割线 30 | 31 | $bg-color: #FBFBFB; //主背景色,列表分割底色 32 | 33 | $bg-sup: #EDEDED; //辅助背景色 34 | 35 | $split-color: #B5B5B5; //tab按钮,强分割线 36 | 37 | $font-color: #333; //主要⽂字 导航默认⽂字 标题⽂字 38 | 39 | $font-second: #4D4D4D; //⼆级标题 重要提⽰ 40 | 41 | $font-third: #666; //⼆级标题 列表标题 42 | 43 | $text-color: #999; //正⽂颜⾊ 辅助信息 ⽂本框默认内容 44 | 45 | $note-color: #FF2424; //注释、 提醒 46 | 47 | $white-color: #fff; //白色 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /web/src/assets/base/css/headMenu.scss: -------------------------------------------------------------------------------- 1 | //顶部导航栏样式 2 | $head-menu-color: if($head-theme=='light', #fff, $base-color); 3 | $background-color: if($head-theme=='light', $base-color, $base-color-blue); 4 | $color: if($head-theme=='light', #fff, #fff); 5 | $focus-color: if($head-theme=='light', #909399, #fff); 6 | $background-color-hover: if($head-theme=='light', #fff, $base-color-blue); 7 | $color-hover: if($head-theme=='light', $base-color, #fff); 8 | 9 | .el-menu { 10 | background-color: $head-menu-color; 11 | } 12 | 13 | .el-menu-item { 14 | font-size: 16px; 15 | } 16 | 17 | .el-menu-demo li.el-submenu div.el-submenu__title { 18 | font-size: 16px!important; 19 | } 20 | 21 | ul.el-menu--popup-bottom-start div li.el-menu-item { 22 | font-size: 14px; 23 | } 24 | 25 | li.el-submenu div.el-submenu__title { 26 | font-size: 14px; 27 | } 28 | 29 | .el-menu--horizontal .el-menu .el-menu-item, .el-menu--horizontal .el-menu .el-submenu__title { 30 | color: $focus-color; 31 | background-color: $head-menu-color; 32 | } 33 | 34 | .el-menu--horizontal > .el-menu-item, .el-submenu__title i, .el-menu--horizontal > .el-submenu .el-submenu__title { 35 | color: $focus-color; 36 | } 37 | 38 | .el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-submenu.is-active .el-submenu__title { 39 | border-bottom: 2px solid $color-hover; 40 | color: $color-hover; 41 | } 42 | 43 | .el-menu--horizontal .el-menu .el-menu-item.is-active, .el-menu--horizontal .el-menu .el-submenu__title.is-active { 44 | background-color: $background-color !important; 45 | color: $color !important; 46 | } 47 | 48 | .el-menu--horizontal .el-menu-item:not(.is-disabled):focus, .el-menu--horizontal .el-menu-item:not(.is-disabled):hover { 49 | color: $color-hover; 50 | background-color: $background-color-hover; 51 | } 52 | 53 | .el-dropdown-menu__item--divided:before, .el-menu, .el-menu--horizontal > .el-menu-item:not(.is-disabled):focus, .el-menu--horizontal > .el-menu-item:not(.is-disabled):hover, .el-menu--horizontal > .el-submenu .el-submenu__title:hover { 54 | color: $color-hover; 55 | background-color: $head-menu-color; 56 | } 57 | 58 | .el-menu--horizontal .el-menu .el-submenu__title:hover { 59 | color: $color-hover; 60 | } 61 | 62 | .el-menu--horizontal .el-menu .el-menu-item.is-active, .el-menu--horizontal .el-menu .el-submenu.is-active > .el-submenu__title { 63 | color: $color-hover; 64 | } 65 | -------------------------------------------------------------------------------- /web/src/assets/base/font/bkicon/Read Me.txt: -------------------------------------------------------------------------------- 1 | Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. 2 | 3 | To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts 4 | 5 | You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. 6 | 7 | You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. 8 | -------------------------------------------------------------------------------- /web/src/assets/base/font/bkicon/demo-files/demo.js: -------------------------------------------------------------------------------- 1 | if (!('boxShadow' in document.body.style)) { 2 | document.body.setAttribute('class', 'noBoxShadow'); 3 | } 4 | 5 | document.body.addEventListener("click", function(e) { 6 | var target = e.target; 7 | if (target.tagName === "INPUT" && 8 | target.getAttribute('class').indexOf('liga') === -1) { 9 | target.select(); 10 | } 11 | }); 12 | 13 | (function() { 14 | var fontSize = document.getElementById('fontSize'), 15 | testDrive = document.getElementById('testDrive'), 16 | testText = document.getElementById('testText'); 17 | function updateTest() { 18 | testDrive.innerHTML = testText.value || String.fromCharCode(160); 19 | if (window.icomoonLiga) { 20 | window.icomoonLiga(testDrive); 21 | } 22 | } 23 | function updateSize() { 24 | testDrive.style.fontSize = fontSize.value + 'px'; 25 | } 26 | fontSize.addEventListener('change', updateSize, false); 27 | testText.addEventListener('input', updateTest, false); 28 | testText.addEventListener('change', updateTest, false); 29 | updateSize(); 30 | }()); 31 | -------------------------------------------------------------------------------- /web/src/assets/base/font/bkicon/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/font/bkicon/fonts/icomoon.eot -------------------------------------------------------------------------------- /web/src/assets/base/font/bkicon/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/font/bkicon/fonts/icomoon.ttf -------------------------------------------------------------------------------- /web/src/assets/base/font/bkicon/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/font/bkicon/fonts/icomoon.woff -------------------------------------------------------------------------------- /web/src/assets/base/img/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/img/alipay.png -------------------------------------------------------------------------------- /web/src/assets/base/img/back_forward_16.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1602555963232" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17562" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M499.2 1011.2L0 512 499.2 12.8l89.6 89.6L179.2 512l409.6 409.6z" p-id="17563"></path><path d="M128 448h896v128H128z" p-id="17564"></path></svg> -------------------------------------------------------------------------------- /web/src/assets/base/img/base_information_32.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1603780053233" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3794" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M302.592 421.888h421.376c16.384 0 30.208-13.824 30.208-30.72s-13.312-30.72-30.208-30.72H302.592c-16.384 0-30.208 13.824-30.208 30.72 0.512 16.896 13.824 30.72 30.208 30.72z m120.32-213.504h180.736c49.664 0 90.112-40.96 90.112-91.648 0-50.688-40.448-91.648-90.112-91.648H422.912C373.248 25.6 332.8 66.56 332.8 117.248c0 50.176 40.448 91.136 90.112 91.136z m0-121.856h180.736c16.384 0 30.208 13.824 30.208 30.72s-13.312 30.72-30.208 30.72H422.912c-16.384 0-30.208-13.824-30.208-30.72 0.512-16.896 13.824-30.72 30.208-30.72z m331.264 487.936c0-16.896-13.312-30.208-30.208-30.208H302.592c-16.384 0-30.208 13.824-30.208 30.208 0 16.896 13.312 30.72 30.208 30.72h421.376c16.384-0.512 30.208-14.336 30.208-30.72z m90.112-487.936h-90.112v60.928h90.112c16.384 0 30.208 13.824 30.208 30.72v731.648c0 16.896-13.312 30.72-30.208 30.72H182.272c-16.384 0-30.208-13.824-30.208-30.72V178.176c0-16.896 13.312-30.72 30.208-30.72h90.112V86.528H182.272c-49.664 0-90.112 40.96-90.112 91.648v731.648c0 50.688 40.448 91.648 90.112 91.648h662.016c49.664 0 90.112-40.96 90.112-91.648V178.176c0-50.688-40.448-91.648-90.112-91.648z m-541.696 640c-16.384 0-30.208 13.824-30.208 30.72s13.312 30.72 30.208 30.72h240.64c16.384 0 30.208-13.824 30.208-30.72s-13.312-30.72-30.208-30.72h-240.64z" p-id="3795" fill="#303133"></path></svg> -------------------------------------------------------------------------------- /web/src/assets/base/img/branch_28.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1603445343897" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4721" width="28" height="28" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M786.773 629.76c-69.973 0-129.706 35.84-165.546 90.453L411.307 599.04c13.653-27.307 22.186-56.32 22.186-88.747 0-20.48-3.413-39.253-8.533-56.32l218.453-124.586c35.84 39.253 87.04 63.146 143.36 63.146 107.52 0 196.267-88.746 196.267-196.266C981.333 88.747 894.293 0 785.067 0c-107.52 0-194.56 88.747-194.56 196.267 0 20.48 3.413 39.253 8.533 56.32L380.587 377.173c-35.84-39.253-87.04-63.146-143.36-63.146-107.52 1.706-194.56 88.746-194.56 197.973 0 109.227 87.04 197.973 196.266 197.973 44.374 0 85.334-15.36 117.76-40.96v1.707L593.92 807.253c0 6.827-1.707 13.654-1.707 20.48C590.507 935.253 677.547 1024 785.067 1024c107.52 0 196.266-88.747 196.266-196.267 0-109.226-87.04-197.973-194.56-197.973z m0-551.253c64.854 0 117.76 52.906 117.76 117.76s-52.906 117.76-117.76 117.76c-64.853 0-117.76-52.907-117.76-117.76s51.2-117.76 117.76-117.76zM238.933 629.76c-64.853 0-117.76-52.907-117.76-117.76 0-64.853 52.907-117.76 117.76-117.76s117.76 52.907 117.76 117.76c-1.706 64.853-52.906 117.76-117.76 117.76z m547.84 315.733c-64.853 0-117.76-52.906-117.76-117.76 0-64.853 52.907-117.76 117.76-117.76 64.854 0 117.76 52.907 117.76 117.76-1.706 64.854-54.613 117.76-117.76 117.76z" p-id="4722"></path></svg> -------------------------------------------------------------------------------- /web/src/assets/base/img/branch_32.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1603780349977" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12322" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M704.2 191.9c-77.2 0-140 62.8-140 140 0 66.8 47.4 123.8 111.8 137-2.4 38.2-20.6 58.6-54 84.4-40.8 31.4-93.4 40-130.6 46.8-81.4 14.8-125.8 54-145 80V341.5c30-5.6 57.4-21 78-43.8 23.2-25.8 36-59 36-93.8 0-77.2-62.8-140-140-140s-140 62.8-140 140c0 34 12.4 66.6 34.6 92.2 19.8 22.6 46.2 38.2 75.4 44.6v342.7c-29 6.4-55.6 22-75.4 44.6-22.4 25.4-34.8 58-34.8 92 0 77.2 62.8 140 140 140s140-62.8 140-140c0-46.8-23.2-89.8-61.4-115.8 17.2-19.4 49-39.2 102.2-48.8 43.2-7.8 105.2-19.2 154.8-57.6 47.2-36.4 73.4-73 76-128.6C796.4 456.2 844 399 844 331.9c0.2-77.2-62.6-140-139.8-140z m-468.2 12c0-46.4 37.6-84 84-84s84 37.6 84 84-37.6 84-84 84-84-37.6-84-84z m168.1 616.2c0 46.4-37.6 84-84 84s-84-37.6-84-84 37.6-84 84-84 84 37.6 84 84zM704.2 416c-46.4 0-84-37.6-84-84s37.6-84 84-84 84 37.6 84 84-37.6 84-84 84z m0 0" p-id="12323" fill="#303133"></path></svg> -------------------------------------------------------------------------------- /web/src/assets/base/img/branch_40.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1604305461268" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3929" width="40" height="40" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M896 320c0-70.4-57.6-128-128-128s-128 57.6-128 128c0 57.6 38.4 108.8 89.6 121.6-6.4 51.2-32 89.6-70.4 108.8-44.8 25.6-102.4 25.6-153.6 25.6-57.6 0-115.2 19.2-153.6 57.6v-384C409.6 236.8 448 185.6 448 128c0-70.4-57.6-128-128-128S192 57.6 192 128c0 57.6 38.4 108.8 96 121.6V768c-57.6 19.2-96 70.4-96 128 0 70.4 57.6 128 128 128s128-57.6 128-128c0-57.6-38.4-108.8-96-121.6v-19.2c19.2-70.4 83.2-115.2 153.6-115.2 51.2 0 121.6 0 185.6-32 57.6-32 89.6-89.6 102.4-160 57.6-12.8 102.4-64 102.4-128zM256 128c0-38.4 25.6-64 64-64s64 25.6 64 64-25.6 64-64 64-64-25.6-64-64z m128 768c0 38.4-25.6 64-64 64s-64-25.6-64-64 25.6-64 64-64 64 25.6 64 64z m384-512c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64z" fill="#7E7E7E" p-id="3930"></path></svg> -------------------------------------------------------------------------------- /web/src/assets/base/img/branch_48.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1604305461268" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3929" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M896 320c0-70.4-57.6-128-128-128s-128 57.6-128 128c0 57.6 38.4 108.8 89.6 121.6-6.4 51.2-32 89.6-70.4 108.8-44.8 25.6-102.4 25.6-153.6 25.6-57.6 0-115.2 19.2-153.6 57.6v-384C409.6 236.8 448 185.6 448 128c0-70.4-57.6-128-128-128S192 57.6 192 128c0 57.6 38.4 108.8 96 121.6V768c-57.6 19.2-96 70.4-96 128 0 70.4 57.6 128 128 128s128-57.6 128-128c0-57.6-38.4-108.8-96-121.6v-19.2c19.2-70.4 83.2-115.2 153.6-115.2 51.2 0 121.6 0 185.6-32 57.6-32 89.6-89.6 102.4-160 57.6-12.8 102.4-64 102.4-128zM256 128c0-38.4 25.6-64 64-64s64 25.6 64 64-25.6 64-64 64-64-25.6-64-64z m128 768c0 38.4-25.6 64-64 64s-64-25.6-64-64 25.6-64 64-64 64 25.6 64 64z m384-512c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64z" fill="#7E7E7E" p-id="3930"></path></svg> -------------------------------------------------------------------------------- /web/src/assets/base/img/execute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/img/execute.png -------------------------------------------------------------------------------- /web/src/assets/base/img/level1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/img/level1.png -------------------------------------------------------------------------------- /web/src/assets/base/img/level2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/img/level2.png -------------------------------------------------------------------------------- /web/src/assets/base/img/level3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/img/level3.png -------------------------------------------------------------------------------- /web/src/assets/base/img/logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/img/logo-white.png -------------------------------------------------------------------------------- /web/src/assets/base/img/wechatpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/base/img/wechatpay.png -------------------------------------------------------------------------------- /web/src/assets/custom/css/common.scss: -------------------------------------------------------------------------------- 1 | // 公共样式 2 | // 外边距 3 | .margin-0 { 4 | margin: 0 !important; 5 | } 6 | 7 | .margin-10 { 8 | margin: 10px; 9 | } 10 | .margin-8 { 11 | margin: 8px; 12 | } 13 | 14 | .margin-20 { 15 | margin: 20px; 16 | } 17 | 18 | .margin-top5 { 19 | margin-top: 5px; 20 | } 21 | 22 | .margin-top10 { 23 | margin-top: 10px; 24 | } 25 | 26 | .margin-top15 { 27 | margin-top: 15px; 28 | } 29 | 30 | .margin-top20 { 31 | margin-top: 20px; 32 | } 33 | 34 | .margin-top25 { 35 | margin-top: 25px; 36 | } 37 | 38 | .margin-top30 { 39 | margin-top: 30px; 40 | } 41 | 42 | .margin-top40 { 43 | margin-top: 40px; 44 | } 45 | 46 | .margin-bottom10 { 47 | margin-bottom: 10px; 48 | } 49 | 50 | .margin-left10 { 51 | margin-left: 10px; 52 | } 53 | 54 | .margin-left20 { 55 | margin-left: 20px; 56 | } 57 | 58 | .margin-right10 { 59 | margin-right: 10px; 60 | } 61 | 62 | // 内边距 63 | .padding-0 { 64 | padding: 0 !important; 65 | } 66 | 67 | .padding-5 { 68 | padding: 5px !important; 69 | } 70 | 71 | .padding-10 { 72 | padding: 10px !important; 73 | } 74 | .padding-16 { 75 | padding: 16px !important; 76 | } 77 | .padding-top10 { 78 | padding-top: 10px; 79 | } 80 | 81 | .padding-bottom10 { 82 | padding-bottom: 10px; 83 | } 84 | 85 | .padding-left10 { 86 | padding-left: 10px; 87 | } 88 | 89 | .padding-right10 { 90 | padding-right: 10px; 91 | } 92 | 93 | // 小手 94 | .pointer { 95 | cursor: pointer; 96 | } 97 | 98 | // 浮动 99 | .float-left { 100 | float: left; 101 | } 102 | 103 | .float-right { 104 | float: right; 105 | } 106 | 107 | // 文本 108 | .text-left { 109 | text-align: left; 110 | } 111 | 112 | .text-center { 113 | text-align: center; 114 | } 115 | 116 | .text-right { 117 | text-align: right; 118 | } 119 | 120 | //字体 121 | .font-bold { 122 | font-weight: bold; 123 | } 124 | 125 | .font-14 { 126 | font-size: 14px !important; 127 | } 128 | 129 | .font-16 { 130 | font-size: 16px !important; 131 | } 132 | 133 | .font-18 { 134 | font-size: 18px !important; 135 | } 136 | 137 | .font-20 { 138 | font-size: 18px !important; 139 | } 140 | 141 | //display 142 | .dis-inline { 143 | display: inline-block; 144 | } 145 | -------------------------------------------------------------------------------- /web/src/assets/custom_icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/custom_icon/iconfont.ttf -------------------------------------------------------------------------------- /web/src/assets/custom_icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/custom_icon/iconfont.woff -------------------------------------------------------------------------------- /web/src/assets/custom_icon/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/src/assets/custom_icon/iconfont.woff2 -------------------------------------------------------------------------------- /web/src/assets/index.js: -------------------------------------------------------------------------------- 1 | //样式统一引入 2 | import './base/css/base.scss' 3 | import './base/css/leftMenu.scss' 4 | // import './base/font/bkicon/style.css' 5 | import './base/css/other.scss' 6 | import './base/css/headMenu.scss' 7 | import './base/css/unify.scss' 8 | import './custom/css/common.scss' 9 | -------------------------------------------------------------------------------- /web/src/common/date.js: -------------------------------------------------------------------------------- 1 | function getMonthLength(date) { 2 | const d = new Date(date) 3 | d.setMonth(d.getMonth() + 1) 4 | d.setDate('1') 5 | d.setDate(d.getDate() - 1) 6 | return d.getDate() 7 | } 8 | 9 | export function getYearWeekDay(str) { 10 | const arr = [] 11 | for (let i = 1; i <= 12; i++) { 12 | const days = getMonthLength(`${str}-${i}-01`) 13 | for (let j = 1; j <= days; j++) { 14 | if (new Date(`${str}-${i}-${j}`).getDay() === 0 || new Date(`2021-${i}-${j}`).getDay() === 6) { 15 | if ((i > 0 && i < 10) && (j > 0 && j < 10)) { 16 | arr.push(`${str}-0${i}-0${j}`) 17 | } 18 | if ((i > 0 && i < 10) && j >= 10) { 19 | arr.push(`${str}-0${i}-${j}`) 20 | } 21 | if (i >= 10 && (j > 0 && j < 10)) { 22 | arr.push(`${str}-${i}-0${j}`) 23 | } 24 | if (i >= 10 && j >= 10) { 25 | arr.push(`${str}-${i}-${j}`) 26 | } 27 | } 28 | } 29 | } 30 | return arr 31 | } 32 | 33 | export function getWorkDays(str) { 34 | const arr = [] 35 | for (let i = 1; i <= 12; i++) { 36 | const days = getMonthLength(`${str}-${i}-01`) 37 | for (let j = 1; j <= days; j++) { 38 | if (new Date(`${str}-${i}-${j}`).getDay() !== 0 && new Date(`2021-${i}-${j}`).getDay() !== 6) { 39 | if ((i > 0 && i < 10) && (j > 0 && j < 10)) { 40 | arr.push(`${str}-0${i}-0${j}`) 41 | } 42 | if ((i > 0 && i < 10) && j >= 10) { 43 | arr.push(`${str}-0${i}-${j}`) 44 | } 45 | if (i >= 10 && (j > 0 && j < 10)) { 46 | arr.push(`${str}-${i}-0${j}`) 47 | } 48 | if (i >= 10 && j >= 10) { 49 | arr.push(`${str}-${i}-${j}`) 50 | } 51 | } 52 | } 53 | } 54 | return arr 55 | } 56 | -------------------------------------------------------------------------------- /web/src/common/message.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | const vm = new Vue() 4 | 5 | const cwMessage = function(data, theme) { 6 | if (typeof data === 'string') { 7 | vm.$bkMessage({ 8 | theme: theme, 9 | message: data, 10 | delay: 1000 11 | }) 12 | } 13 | } 14 | const types = [{ 15 | key: 'info', 16 | theme: 'primary' 17 | }, 18 | { 19 | key: 'primary', 20 | theme: 'primary' 21 | }, 22 | { 23 | key: 'error', 24 | theme: 'error' 25 | }, 26 | { 27 | key: 'success', 28 | theme: 'success' 29 | }, 30 | { 31 | key: 'warning', 32 | theme: 'warning' 33 | } 34 | ] 35 | types.forEach(t => { 36 | cwMessage[t.key] = (data) => { 37 | return cwMessage(data, t) 38 | } 39 | }) 40 | export default cwMessage 41 | -------------------------------------------------------------------------------- /web/src/common/store.js: -------------------------------------------------------------------------------- 1 | import { 2 | validatenull 3 | } from './util.js' 4 | 5 | /** 6 | * 存储localStorage 7 | */ 8 | export const setStore = (params = {}) => { 9 | const { 10 | name, 11 | content 12 | } = params 13 | const obj = { 14 | dataType: typeof content, 15 | content: content, 16 | datetime: new Date().getTime() 17 | } 18 | window.localStorage.setItem(name, JSON.stringify(obj)) 19 | } 20 | /** 21 | * 获取localStorage 22 | */ 23 | 24 | export const getStore = (params = {}) => { 25 | const { 26 | name 27 | } = params 28 | let obj = {} 29 | obj = window.localStorage.getItem(name) 30 | if (validatenull(obj)) return 31 | obj = JSON.parse(obj) 32 | // if (obj.dataType == 'string') { 33 | // content = obj.content; 34 | // } else if (obj.dataType == 'number') { 35 | // content = Number(obj.content); 36 | // } else if (obj.dataType == 'boolean') { 37 | // content = eval(obj.content); 38 | // } else if (obj.dataType == 'object') { 39 | // content = obj.content; 40 | // } 41 | return obj.content 42 | } 43 | /** 44 | * 删除localStorage 45 | */ 46 | export const removeStore = (params = {}) => { 47 | 48 | } 49 | 50 | /** 51 | * 获取全部localStorage 52 | */ 53 | export const getAllStore = (params = {}) => { 54 | 55 | } 56 | 57 | /** 58 | * 清空全部localStorage 59 | */ 60 | export const clearStore = (params = {}) => { 61 | window.localStorage.clear() 62 | } 63 | -------------------------------------------------------------------------------- /web/src/components/base/magicMenu/container.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div id="container"> 3 | <router-view></router-view> 4 | </div> 5 | 6 | </template> 7 | 8 | <script> 9 | export default { 10 | data() { 11 | return { 12 | } 13 | } 14 | } 15 | </script> 16 | 17 | <style scoped> 18 | #container { 19 | height: calc(100vh - 52px); 20 | } 21 | </style> 22 | -------------------------------------------------------------------------------- /web/src/components/index.js: -------------------------------------------------------------------------------- 1 | // import container from './base/container' 2 | // import header from './base/header' 3 | // import headerMenu from './base/headerMenu' 4 | // import leftMenu from './base/leftMenu' 5 | // import CWView from './element/iView' 6 | // import iViewTwo from './element/iViewTwo' 7 | // import Buttons from './element/Buttons' 8 | // import CWCollapse from './collapse/cw-collapse' 9 | // import CWTable from './table/cw-table' 10 | // import CWTransfer from './transfer/CWTransfer.vue' 11 | // import CWDropDown from './dropDown/dropDown.vue' 12 | // import CWCodeMirror from './codeMirror/codeMirror.vue' 13 | 14 | const components = [ 15 | // container, 16 | // header, 17 | // headerMenu, 18 | // leftMenu, 19 | // CWView, 20 | // CWTable, 21 | // CWDropDown, 22 | // iViewTwo, 23 | // Buttons, 24 | // CWCollapse, 25 | // CWCodeMirror, 26 | // CWTransfer 27 | ] 28 | 29 | const install = function(Vue) { 30 | components.forEach(component => { 31 | Vue.component(component.name, component) 32 | }) 33 | } 34 | export default install 35 | -------------------------------------------------------------------------------- /web/src/components/iview/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | //按需引入iview 3 | import { 4 | Tag, 5 | Drawer, 6 | Poptip 7 | } from 'view-design'; 8 | 9 | Vue.component('Tag', Tag); 10 | Vue.component('Drawer', Drawer); 11 | Vue.component('Poptip', Poptip); 12 | -------------------------------------------------------------------------------- /web/src/fiter/index.js: -------------------------------------------------------------------------------- 1 | import './validator/validator' 2 | -------------------------------------------------------------------------------- /web/src/fiter/validator/validator.js: -------------------------------------------------------------------------------- 1 | // 表单验证 2 | import Vue from 'vue' 3 | import VeeValidate, { 4 | Validator 5 | } from 'vee-validate' 6 | import VueI18n from 'vue-i18n' 7 | import zhCN from 'vee-validate/dist/locale/zh_CN' 8 | 9 | // 国际化 10 | Vue.use(VueI18n) 11 | const i18n = new VueI18n({ 12 | locale: 'zh_CN' 13 | }) 14 | 15 | // 自定义validate 16 | const Dictionary = { 17 | zhCN: { 18 | messages: { 19 | required: field => '请输入' + field 20 | }, 21 | attributes: { 22 | name: '账号' 23 | } 24 | } 25 | } 26 | 27 | // 自定义validate error 信息 28 | Validator.localize(Dictionary) 29 | 30 | // 自定义表单 31 | Validator.extend('phone', { 32 | messages: { 33 | zhCN: field => field + '必须是11位手机号码' 34 | }, 35 | validate: value => { 36 | return value.length === 11 && /^((13|14|15|17|18)[0-9]{1}\d{8})$/.test(value) 37 | } 38 | }) 39 | 40 | Vue.use(VeeValidate, { 41 | i18n, 42 | // events:'', // 添加校验事件 43 | i18nRootKey: 'validation', 44 | dictionary: { 45 | zhCN 46 | }, 47 | fieldsBagName: 'fieldBags' // fields重命名,和ElementUI冲突 48 | }) 49 | -------------------------------------------------------------------------------- /web/src/router/_import_development.js: -------------------------------------------------------------------------------- 1 | module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+ 2 | -------------------------------------------------------------------------------- /web/src/router/_import_production.js: -------------------------------------------------------------------------------- 1 | module.exports = file => () => import('@/views' + file + '.vue') 2 | -------------------------------------------------------------------------------- /web/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | const originalPush = Router.prototype.push 5 | Router.prototype.push = function(location) { 6 | return originalPush.call(this, location).catch(err => err) 7 | } 8 | Vue.use(Router) 9 | 10 | const constantRouterMap = [] 11 | 12 | export default new Router({ 13 | routes: constantRouterMap 14 | }) 15 | -------------------------------------------------------------------------------- /web/src/vuex/actions.js: -------------------------------------------------------------------------------- 1 | // 给action注册事件处理函数 当函数被触发的时候,将该状态提交到mutations中处理好多 2 | export function modifyAName({commit}, name) { 3 | return commit('modifyName', name) 4 | } 5 | -------------------------------------------------------------------------------- /web/src/vuex/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | getUserRole: state => state.common.userRole, 3 | geFullPath: state => state.common.fullPath, 4 | getHasMsg: state => state.common.hasMsg 5 | } 6 | export default getters 7 | -------------------------------------------------------------------------------- /web/src/vuex/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import common from './module/common.js' 4 | import getters from './getters.js' 5 | 6 | Vue.use(Vuex) 7 | 8 | const store = new Vuex.Store({ 9 | modules: { 10 | common // 公共属性 11 | }, 12 | getters 13 | }) 14 | 15 | export default store 16 | -------------------------------------------------------------------------------- /web/src/vuex/module/common.js: -------------------------------------------------------------------------------- 1 | const common = { 2 | state: { 3 | defaultTableHeight: 800, 4 | userRole: '', 5 | fullPath: '', 6 | hasMsg: false 7 | }, 8 | mutations: { 9 | setDefaultTableHeight: (state, val) => { 10 | state.defaultTableHeight = val 11 | }, 12 | setUserRole: (state, val) => { 13 | state.userRole = val 14 | }, 15 | setFullPath: (state, val) => { 16 | state.fullPath = val 17 | }, 18 | setHasMsg: (state, val) => { 19 | state.hasMsg = val 20 | } 21 | } 22 | } 23 | 24 | export default common 25 | -------------------------------------------------------------------------------- /web/static/css/.gitkeep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /web/static/img/.gitkeep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /web/static/img/favicon_64.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/static/img/favicon_64.ico -------------------------------------------------------------------------------- /web/static/img/music-tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/static/img/music-tag.png -------------------------------------------------------------------------------- /web/static/img/music_null-cutout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhongc/music-tag-web/906a14b8a55b677e2d61a108d12878f6695d730a/web/static/img/music_null-cutout.png -------------------------------------------------------------------------------- /web/static/js/.gitkeep: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | --------------------------------------------------------------------------------