The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .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 | 


--------------------------------------------------------------------------------