-
Notifications
You must be signed in to change notification settings - Fork 0
Dev #48
base: master
Are you sure you want to change the base?
Dev #48
Changes from all commits
fdd2287
ccf2e86
c23b4b2
b0866e7
8ef6557
94533bb
ffad299
fc50c9d
402b696
a654885
f418835
4462f5e
2848c9b
a2a62bb
a2011fd
f33375a
24a9ae5
3d802e7
3ee0ece
b84ceda
3004a53
5300833
e58e22a
ac265ee
df4c6ab
6f2ac42
1616ed0
df1e3ec
f9d5514
9903892
935cace
d53133a
3b760ee
e200d8b
ec18cf3
3821c1e
c861af1
b460a48
8a68b57
bb3f6fa
28faf3b
e125718
a93cce0
bc68c2a
8cfbfdd
972b2b6
e3bd8ae
ed1a20b
a4cde3f
b574a57
f462933
06214a7
fe468c7
4563152
8a0183d
0126943
758fd54
8528bea
dd51614
ed43f83
4ac1e60
f5f8a94
bda2ac2
2104dbc
8fd40db
e3a15c9
7640fcc
582b60f
1e42a7c
0116e78
79f112c
bc8b856
22c797c
7ae0f04
82d34e6
8a36126
d9bef00
93c77c8
be14646
8303028
29fca5a
847d37a
92bd784
fdf6aa6
b45341c
bfbe767
23dc1d1
299e3a3
6fc64de
8fe2f1a
241b4b3
ece1343
d630c66
09e658e
6eeb10c
ea5b654
71e7b76
418a44c
fadb3ff
e31e020
cfb3913
c16f7fe
23c3f60
29bf482
368f73e
11bbb40
f5533b7
36a2991
2dd6a7e
2b997ec
4e9019c
3ce96be
19aec64
611f774
968537e
c59f87f
3c524f2
a99df1c
a6b8daa
a69d9c6
a65a415
62d11f2
5e85f43
1a996f2
8f39a04
6063b38
9668ecf
11caf90
bc28604
3fbc550
f7501df
9a37800
3009980
43fb584
1210833
b8014d3
d62d4fd
954c965
8635a54
554915f
a2e982c
5a14839
dab8c14
da36fdd
6605bf0
a93c6b3
c6eb2f1
9eefc06
78d9651
ae41d76
1e7ee14
3c1599c
05a4a44
e03949f
16baeb3
f413aad
3c27777
7fc2737
8bfa36d
f87acff
a549664
94c4002
e19acb1
cc1ba83
553263e
7840cdb
a3d49b8
6e54a63
4be1d82
2b77c72
c6b3f66
4aa5c92
6126b43
5ecb334
478f3e2
3dc75ce
70c7046
4a5f832
979da8a
6fed927
3384e1c
74d577d
ac052cf
1413e1b
4dcda3c
2f3c53a
1b4f47d
d0a9ae5
f0f52f7
dd5f1f2
bfce75e
ae31225
46a247e
933807b
ee2d622
a34e655
457fd4b
1f905ba
b5a91a7
61cd413
9796cff
02626e2
4854122
5dd1afc
3a7a6bd
0bf8e51
5fdff07
93860b5
e5907af
422bf83
82863ff
817190a
743e584
481dbcd
7607c84
1af9279
c444d7b
12fa4bd
487f8d9
ef6a5af
600a99b
b33f088
37f0adb
cabdaa5
1360f49
f57094d
1e8e3d3
2b56295
05942bb
5de3cdd
d9f5156
89017c4
fbbe0c3
3ac77e7
6d0e2d8
e102390
8117edf
520f0ab
7b65477
49849cc
d79e2df
586031f
a881c3c
0531e75
cad1686
26615dd
c3b0cc9
70cb409
7fdf466
8838653
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -93,6 +93,7 @@ venv.bak/ | |
| # Spyder project settings | ||
| .spyderproject | ||
| .spyproject | ||
| yandex_tokens.py | ||
|
|
||
| # Rope project settings | ||
| .ropeproject | ||
|
|
@@ -105,3 +106,12 @@ venv.bak/ | |
|
|
||
| # direnv | ||
| .envrc | ||
|
|
||
| # audio files: | ||
| app/media/ | ||
| media/ | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not a great idea to store files created by your code in the same directories as the code itself |
||
|
|
||
| # ideas | ||
| .idea/ | ||
| .vscode | ||
| app.db | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # We simply inherit the Python 3 image. This image does | ||
| # not particularly care what OS runs underneath | ||
| FROM python:3 | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not use a ready-made flask image? |
||
| # Set an environment variable with the directory | ||
| # where we'll be running the app | ||
| ENV APP /app | ||
| # Create the directory and instruct Docker to operate | ||
| # from there from now on | ||
| RUN mkdir $APP | ||
| WORKDIR $APP | ||
| # Expose the port uWSGI will listen on | ||
| EXPOSE 5000 | ||
| # Copy the requirements file in order to install | ||
| # Python dependencies | ||
| COPY requirements.txt . | ||
| # App dependencies | ||
| RUN apt-get update && apt-get install -y ffmpeg | ||
| # Install Python dependencies | ||
| RUN pip install -r requirements.txt | ||
| # We copy the rest of the codebase into the image | ||
| COPY . . | ||
| # Finally, we run uWSGI with the ini file we | ||
| # created earlier | ||
| CMD [ "uwsgi", "--ini", "app.ini" ] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No new line at end of file |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| FROM nginx:latest | ||
| # Nginx will listen on this port | ||
| EXPOSE 80 | ||
| # Remove the default config file that | ||
| # /etc/nginx/nginx.conf includes | ||
| RUN rm /etc/nginx/conf.d/default.conf | ||
| # We copy the requirements file in order to install | ||
| # Python dependencies | ||
| COPY app.conf /etc/nginx/conf.d | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No new line at end of file |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # HOW TO RUN FLASK APP | ||
| ```sh | ||
| export FLASK_APP=eriwan_podcast.py | ||
| export FLASK_DEBUG=1 | ||
|
|
||
| flask db init | ||
| flask db migrate | ||
| flask db upgrade | ||
|
|
||
| flask run | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,31 +1,33 @@ | ||
| # Eriwan | ||
| This is a repository for the test task of Spherical Internship August 2019 | ||
| # Eriwan. Test task of Spherical Internship August 2019. Version 1.0 | ||
|
|
||
| First call agenda: | ||
| 1. Linter tool - flake8 | ||
| 2. Git branch strategy | ||
| 3. Project environment: optional (majority for flake8) | ||
| 4. Python version: 3.7 | ||
| 5. Pytest/unitest/nose: optional (majority for pytest) | ||
| 6. Code Master: pending | ||
| 6.1. Code review: first responder | ||
| 7. Data Base: Sqlite | ||
| 8. Flask | ||
| 9. Queue: celery? | ||
| 10. Upload file size limits: 20 Megabytes | ||
| 11. Audio file format: mp3? | ||
| 12. Frontend: Bootsrap + jinja | ||
| ## Eriwan | ||
| ------------- | ||
| Web servis for public podcast creation where each user can add episodes and | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Spelling. I will only make this comment once about human-readable content here, though spelling is not great across the board. Spelling is very important. Misspelled words will not be found by search, making navigation in your code, comments and documentation very difficult. |
||
| admin could add jokes. | ||
| Jokes go through speech syntesis and concatinate with jingle before and after. | ||
| Episode's name go through speech syntesis and concatinate with episodes. | ||
| Podcast destributed by RSS/Atom feed. | ||
| Servis has admin and user authorisation forms. | ||
| Also admin can delete or change jokes. | ||
|
|
||
| Podcast structure: | ||
| 1. 1st audio: jingle + joke + jungle; | ||
| 2. 2nd audio: name of episode + episode | ||
| 3. Podcast language: Russian | ||
| 4. Speech synthesis: gTTS | ||
|
|
||
| ## Usage | ||
| ------------- | ||
| To use Eriwan you should follow next steps: | ||
| ``` | ||
| export FLASK_APP=eriwan_podcast.py | ||
| flask run | ||
| ``` | ||
| or just go to http://68.183.145.62/ | ||
| Required modules you can find in requirements.txt | ||
|
|
||
| Poll results: | ||
| 1. First meeting time: 10:00 (GMT+3) | ||
| 2. Second meeting saturday 19.00 (GMT+3) | ||
| ## Contributing | ||
| ------------- | ||
| It's a hackathon-like project, we know this might not be the perfect. If you have any ideas, just open an issue and tell us what you think. | ||
|
|
||
| If you'd like to contribute, please fork the repository and make changes as you'd like. Pull requests are warmly welcome. | ||
|
|
||
| 3. Communication language: Russian | ||
|
|
||
| ## Licensing | ||
| ------------- | ||
| This project is licensed under MIT license. This license allows unlimited redistribution for any purpose as long as its copyright notices and the license's disclaimers of warranty are maintained. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| server { | ||
| listen 80; | ||
| root /usr/share/nginx/html; | ||
| location / { try_files $uri @app; } | ||
| location @app { | ||
| include uwsgi_params; | ||
| uwsgi_pass flask:5000; | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No new line at end of file |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| [uwsgi] | ||
| protocol = uwsgi | ||
| ; This is the name of our Python file | ||
| ; minus the file extension | ||
| module = eriwan_podcast | ||
| ; This is the name of the variable | ||
| ; in our script that will be called | ||
| callable = app | ||
| master = true | ||
| ; Set uWSGI to start up 5 workers | ||
| processes = 5 | ||
| ; We use the port 5000 which we will | ||
| ; then expose on our Dockerfile | ||
| socket = 0.0.0.0:5000 | ||
| vacuum = true | ||
| die-on-term = true | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No new line at end of file |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| from flask import Flask | ||
| from flask_migrate import Migrate | ||
| from flask_sqlalchemy import SQLAlchemy | ||
| from flask_login import LoginManager | ||
| from flask_bootstrap import Bootstrap | ||
| from flask_dropzone import Dropzone | ||
| from flask_wtf.csrf import CSRFProtect | ||
|
|
||
| from config import Config | ||
|
|
||
| app = Flask(__name__) | ||
|
|
||
| # using Config class from ./config.py | ||
| app.config.from_object(Config) | ||
|
|
||
| # database | ||
| db = SQLAlchemy(app) | ||
| migrate = Migrate(app, db) | ||
|
|
||
| # authorization | ||
| login_manager = LoginManager(app) | ||
|
|
||
| #styles | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Formatting: either leave a space after the |
||
| bootstrap = Bootstrap(app) | ||
|
|
||
| from .rss import RssResponse | ||
| app.response_class = RssResponse | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is happening here? |
||
|
|
||
| # podcast upload dropzone | ||
| dropzone = Dropzone(app) | ||
| csrf = CSRFProtect(app) | ||
|
|
||
|
|
||
| # The routes module is imported at the bottom and not at the top of the script | ||
| # as it is always done. The bottom import is a workaround to circular imports, | ||
| # a common problem with Flask applications. | ||
| from app import routes, models, errors | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| from pydub import AudioSegment | ||
| from gtts import gTTS | ||
| import tempfile | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import order: 1. stdlib 2. third-party modules 3. project-local modules. Within each section: |
||
|
|
||
|
|
||
| def text_to_speech(text): | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all method names shall contain a verb. All methods do something and their names should clearly state what they do |
||
| """ | ||
| takes text, makes Russian speech, saved into temporary mp3 file | ||
| """ | ||
| temporary_file = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) | ||
| tts = gTTS(text=text, lang='ru') | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and across the project: use one quote style. Preferably single quotes, but most importantly one style across the project |
||
| tts.save(temporary_file.name) | ||
|
|
||
| return temporary_file.name | ||
|
|
||
|
|
||
| def concatenate_audios(path_list, out_path): | ||
| """ | ||
| Concatenate audios into one file | ||
| :param out_path: path for saving mp3 file | ||
| :param path_list: audio path list | ||
| :return: | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, what does this method return? Generally, what happens if it couldn't deliver the expected result? |
||
| """ | ||
|
|
||
| res = AudioSegment.empty() | ||
| for audio_path in path_list: | ||
| res += AudioSegment.from_mp3(audio_path) | ||
| res.export(out_path, format='mp3') | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Handle route and server exceptions | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. useless comment |
||
| from flask import render_template | ||
| from app import app | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better leave an empty line between groups of imports (see above) |
||
| from app import db | ||
|
|
||
|
|
||
| @app.errorhandler(404) | ||
| def not_found_error(error): | ||
| return render_template('404.html'), 404 | ||
|
|
||
|
|
||
| @app.errorhandler(500) | ||
| def internal_error(error): | ||
| db.session.rollback() | ||
| return render_template('500.html'), 500 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| from wtforms import StringField, PasswordField, SubmitField, BooleanField | ||
| from wtforms.validators import DataRequired, Length, Email, EqualTo,\ | ||
| ValidationError | ||
| from flask_wtf import FlaskForm | ||
| from flask_wtf.file import FileField, FileAllowed, FileRequired | ||
|
|
||
| from app.models import User | ||
|
|
||
|
|
||
| class RegistrationForm(FlaskForm): | ||
| username = StringField( | ||
| 'Имя пользователя', | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and ahead: mixing code and content, especially content in non-Latin script, is a bad idea. |
||
| render_kw={"placeholder": "Ваше имя пользователя"}, | ||
| validators=[ | ||
| DataRequired(), | ||
| Length(min=2, max=64)]) | ||
| email = StringField( | ||
| 'Почтовый ящик', | ||
| render_kw={"placeholder": "you@example.com"}, | ||
| validators=[ | ||
| DataRequired(), | ||
| Email()]) | ||
| password = PasswordField( | ||
| 'Пароль', | ||
| validators=[ | ||
| DataRequired(), | ||
| Length(min=3, max=25)]) | ||
| confirm_password = PasswordField( | ||
| 'Подтверждение пароля', | ||
| validators=[ | ||
| DataRequired(), | ||
| Length(min=3, max=25), | ||
| EqualTo('password')]) | ||
| submit = SubmitField('Зарегистрироваться') | ||
|
|
||
| @staticmethod | ||
| def validate_username(self, username): | ||
| user = User.query.filter_by(username=username.data).first() | ||
| if user: | ||
| raise ValidationError('Это имя пользователя уже занято. Пожалуйста \ | ||
| выберите другое.') | ||
|
|
||
| @staticmethod | ||
| def validate_email(self, email): | ||
| email = User.query.filter_by(email=email.data).first() | ||
| if email: | ||
| raise ValidationError('Этот почтовый ящик уже занят. Пожалуйста \ | ||
| выберите другое.') | ||
|
|
||
|
|
||
| class LoginForm(FlaskForm): | ||
| username = StringField("Имя пользователя", validators=[DataRequired()]) | ||
| password = PasswordField("Пароль", validators=[DataRequired()]) | ||
| remember_me = BooleanField("Запомнить меня") | ||
| submit = SubmitField("Войти") | ||
|
|
||
|
|
||
| class UploadJokeForm(FlaskForm): | ||
| """ | ||
| Form for Jokes: | ||
| :parameter: | ||
| text - Joke text; | ||
| submit - submit button; | ||
| """ | ||
| text = StringField('Текст шутки', validators=[DataRequired()]) | ||
| submit = SubmitField('Сохранить') | ||
|
|
||
|
|
||
| class EditJokeForm(FlaskForm): | ||
| text = StringField("Текст", validators=[DataRequired()]) | ||
| submit = SubmitField("Редактировать") | ||
|
|
||
|
|
||
| class EditUserProfileForm(FlaskForm): | ||
| username = StringField( | ||
| 'Имя пользователя', | ||
| render_kw={"placeholder": "Новое имя пользователя"}, | ||
| validators=[ | ||
| DataRequired(), | ||
| Length(min=2, max=64)]) | ||
| old_password = PasswordField( | ||
| 'Старый пароль', | ||
| validators=[ | ||
| DataRequired(), | ||
| Length(min=3, max=25)]) | ||
| password = PasswordField( | ||
| 'Новый пароль', | ||
| validators=[ | ||
| DataRequired(), | ||
| Length(min=3, max=25)]) | ||
| confirm_password = PasswordField( | ||
| 'Подтверждение пароля', | ||
| validators=[ | ||
| DataRequired(), | ||
| Length(min=3, max=25), | ||
| EqualTo('password')]) | ||
| submit = SubmitField('Редактировать') | ||
|
|
||
|
|
||
| class EpisodeUploadForm(FlaskForm): | ||
| file = FileField('Upload podcast', validators=[ | ||
| FileRequired(), | ||
| FileAllowed(['mp3'], "Wrong format! Only mp3 format audio files") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you use different quotes style?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so, we are mixing interface languages?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... and single and double quotes on the same line! |
||
| ]) | ||
| title = StringField('Имя подкаста', validators=[DataRequired()]) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we using yandex tokens in the final version?