├── audiofield ├── middleware │ ├── __init__.py │ └── threadlocals.py ├── migrations │ ├── __init__.py │ ├── 0002_auto_20180121_0750.py │ ├── 0003_auto_20220520_1655.py │ └── 0001_initial.py ├── locale │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── pt │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── zh │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── static │ └── audiofield │ │ ├── swf │ │ ├── soundmanager2.swf │ │ ├── soundmanager2_debug.swf │ │ ├── soundmanager2_flash9.swf │ │ ├── soundmanager2_flash9_debug.swf │ │ └── soundmanager2_flash_xdomain.zip │ │ ├── page-player │ │ ├── image │ │ │ ├── divot.png │ │ │ ├── divot-bottom.png │ │ │ └── top-highlight.png │ │ ├── css │ │ │ ├── demo.css │ │ │ ├── optional-annotations.css │ │ │ ├── optional-themes.css │ │ │ └── page-player.css │ │ ├── basic.html │ │ └── script │ │ │ └── optional-page-player-metadata.js │ │ ├── flashblock │ │ ├── basic.html │ │ ├── method1 │ │ │ ├── flashblock.css │ │ │ ├── flashblock.js │ │ │ └── index.html │ │ ├── flashblock.css │ │ └── index.html │ │ └── script │ │ └── soundmanager2-nodebug-jsmin.js ├── __init__.py ├── forms.py ├── admin.py ├── tests.py ├── templates │ └── common_audiofield.html ├── tasks.py ├── models.py ├── widgets.py └── fields.py ├── requirements.txt ├── CONTRIBUTORS ├── audio_samples ├── duck.wav ├── rain.mp3 ├── select.mp3 ├── walking.mp3 ├── webconf.wav ├── sample_ogg.ogg ├── Rain on Car Roof.aac └── sine, square, sawtooth, rando.mp3 ├── docs ├── source │ ├── introduction.rst │ ├── _static │ │ ├── django-admin-audiofield.png │ │ └── django-admin-audiofield-upload.png │ ├── developer-doc │ │ ├── pre-requisite.rst │ │ ├── objects-description.rst │ │ ├── testing.rst │ │ └── form.rst │ ├── developer-doc.rst │ ├── index.rst │ ├── installation-overview.rst │ ├── includes │ │ └── introduction.txt │ └── conf.py ├── Makefile └── make.bat ├── MANIFEST.in ├── .gitignore ├── RELEASE.txt ├── update_version.sh ├── MIT-LICENSE.txt ├── setup.py ├── HACKING ├── CHANGELOG.rst └── README.rst /audiofield/middleware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /audiofield/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | celery>=3.1.7 2 | django-celery>=3.1.1 3 | six>=1.9 4 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | areski (Areski Belaid) 2 | shrenik (Shrenik Patel) 3 | andrewyager (Andrew Yager) 4 | -------------------------------------------------------------------------------- /audio_samples/duck.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/duck.wav -------------------------------------------------------------------------------- /audio_samples/rain.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/rain.mp3 -------------------------------------------------------------------------------- /audio_samples/select.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/select.mp3 -------------------------------------------------------------------------------- /audio_samples/walking.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/walking.mp3 -------------------------------------------------------------------------------- /audio_samples/webconf.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/webconf.wav -------------------------------------------------------------------------------- /audio_samples/sample_ogg.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/sample_ogg.ogg -------------------------------------------------------------------------------- /audio_samples/Rain on Car Roof.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/Rain on Car Roof.aac -------------------------------------------------------------------------------- /audiofield/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /audiofield/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /audiofield/locale/pt/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/locale/pt/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /audiofield/locale/zh/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/locale/zh/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /docs/source/introduction.rst: -------------------------------------------------------------------------------- 1 | .. _intro: 2 | 3 | ============ 4 | Introduction 5 | ============ 6 | 7 | .. include:: ./includes/introduction.txt 8 | -------------------------------------------------------------------------------- /audio_samples/sine, square, sawtooth, rando.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audio_samples/sine, square, sawtooth, rando.mp3 -------------------------------------------------------------------------------- /docs/source/_static/django-admin-audiofield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/docs/source/_static/django-admin-audiofield.png -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | global-exclude *.pyc 2 | 3 | include README.rst 4 | include MIT-LICENSE.txt 5 | include requirements.txt 6 | 7 | recursive-include audiofield * 8 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/swf/soundmanager2.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/swf/soundmanager2.swf -------------------------------------------------------------------------------- /docs/source/_static/django-admin-audiofield-upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/docs/source/_static/django-admin-audiofield-upload.png -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/image/divot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/page-player/image/divot.png -------------------------------------------------------------------------------- /audiofield/static/audiofield/swf/soundmanager2_debug.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/swf/soundmanager2_debug.swf -------------------------------------------------------------------------------- /audiofield/static/audiofield/swf/soundmanager2_flash9.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/swf/soundmanager2_flash9.swf -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/image/divot-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/page-player/image/divot-bottom.png -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/image/top-highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/page-player/image/top-highlight.png -------------------------------------------------------------------------------- /audiofield/static/audiofield/swf/soundmanager2_flash9_debug.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/swf/soundmanager2_flash9_debug.swf -------------------------------------------------------------------------------- /audiofield/static/audiofield/swf/soundmanager2_flash_xdomain.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/areski/django-audiofield/HEAD/audiofield/static/audiofield/swf/soundmanager2_flash_xdomain.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *dilla* 3 | *.db 4 | *nbproject* 5 | *devserver* 6 | *.idea* 7 | test.db 8 | settings_local.py 9 | docs/build/* 10 | build/ 11 | dist/ 12 | *.egg* 13 | .DS_Store 14 | *sublime* 15 | -------------------------------------------------------------------------------- /RELEASE.txt: -------------------------------------------------------------------------------- 1 | 2 | Release Process 3 | =============== 4 | 5 | 1. Update version info 6 | * README.rst 7 | * audiofield/__init__.py 8 | * docs/conf.py 9 | 10 | 2. git tag -a vX.Y.Z -m 'Version X.Y.Z' 11 | 12 | 3. python setup.py sdist upload 13 | -------------------------------------------------------------------------------- /docs/source/developer-doc/pre-requisite.rst: -------------------------------------------------------------------------------- 1 | .. _prerequisites: 2 | 3 | Prerequisites 4 | ============= 5 | 6 | To fully understand this project, developers will need to have an advanced knowledge of: 7 | - Django : http://www.djangoproject.com/ 8 | - Python : http://www.python.org/ 9 | -------------------------------------------------------------------------------- /docs/source/developer-doc.rst: -------------------------------------------------------------------------------- 1 | .. _developer-doc: 2 | 3 | ======================= 4 | Developer Documentation 5 | ======================= 6 | 7 | Contents: 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | ./developer-doc/pre-requisite.rst 13 | ./developer-doc/objects-description.rst 14 | ./developer-doc/form.rst 15 | ./developer-doc/testing.rst 16 | 17 | -------------------------------------------------------------------------------- /audiofield/migrations/0002_auto_20180121_0750.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.1 on 2018-01-21 07:50 2 | 3 | import audiofield.fields 4 | from django.db import migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('audiofield', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='audiofile', 16 | name='audio_file', 17 | field=audiofield.fields.AudioField(blank=True, upload_to='upload/audiofiles', verbose_name='audio file'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /audiofield/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Django-audiofield is a Django application which allows audio file upload 6 | and conversion to mp3, wav and ogg format. 7 | 8 | It also makes it easy to play the audio files into your django application. 9 | 10 | Project location : https://github.com/Star2Billing/django-audiofield 11 | """ 12 | 13 | __version__ = '0.10.1' # edit also docs/source/conf.py and update requirements.txt 14 | __author__ = "Areski Belaid" 15 | __contact__ = "areski@gmail.com" 16 | __homepage__ = "http://areskibelaid.com/" 17 | __docformat__ = "restructuredtext" 18 | -------------------------------------------------------------------------------- /docs/source/developer-doc/objects-description.rst: -------------------------------------------------------------------------------- 1 | .. _objects-description: 2 | 3 | Objects Description 4 | =================== 5 | 6 | .. _AudioFile-model: 7 | 8 | :class:`AudioFile` 9 | ------------------ 10 | 11 | Describe model of the AudioFile 12 | 13 | **Attributes**: 14 | 15 | * ``name`` - given name to the audio file / not unique . 16 | * ``audio_file`` - path and filename to the audio file. 17 | * ``user`` - Attach user. 18 | * ``created_date`` - record created date. 19 | * ``updated_date`` - record updated date. 20 | 21 | **Name of DB table**: audio_file 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. django-audiofield documentation master file, created by 2 | sphinx-quickstart on Thu Dec 8 12:55:34 2011. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to django-audiofield's documentation! 7 | ============================================= 8 | 9 | :Release: |version| 10 | :Date: |today| 11 | 12 | 13 | Contents: 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | 18 | introduction 19 | installation-overview 20 | developer-doc 21 | 22 | 23 | Indices and tables 24 | ================== 25 | 26 | * :ref:`genindex` 27 | * :ref:`modindex` 28 | * :ref:`search` 29 | -------------------------------------------------------------------------------- /docs/source/developer-doc/testing.rst: -------------------------------------------------------------------------------- 1 | .. _testing: 2 | 3 | Test Case Descriptions 4 | ====================== 5 | 6 | ---------------- 7 | How to run tests 8 | ---------------- 9 | 10 | **1. Run full test suite**:: 11 | 12 | $ python manage.py test --verbosity=2 13 | 14 | **2. Run AudiofileTestCase**:: 15 | 16 | $ python manage.py test audiofield.AudiofieldAdminInterfaceTestCase --verbosity=2 17 | 18 | 19 | .. _audiofield-admin-testcases: 20 | 21 | :class:`AudiofieldAdminInterfaceTestCase` 22 | ----------------------------------------- 23 | 24 | Different test-cases of the audiofield 25 | 26 | **def test_admin_index()** : Test Function to check Admin index page 27 | 28 | **def test_admin_audiofield()** : Test Function to check Audiofield Admin pages 29 | 30 | 31 | -------------------------------------------------------------------------------- /audiofield/migrations/0003_auto_20220520_1655.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.10 on 2022-05-20 14:55 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('audiofield', '0002_auto_20180121_0750'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='audiofile', 17 | options={'permissions': (('can_view_audiofile', 'can see Audio Files'),), 'verbose_name': 'audio file', 'verbose_name_plural': 'audio files'}, 18 | ), 19 | migrations.AddField( 20 | model_name='audiofile', 21 | name='tag', 22 | field=models.CharField(blank=True, help_text='tag used to categorize the audio files', max_length=50, null=True, verbose_name='tag'), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /update_version.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Usage: 3 | # ./update_version.sh 0.10.0 4 | # 5 | 6 | git flow release start v$1 7 | sed -i -e "s/__version__ = '.*'/__version__ = '$1'/g" audiofield/__init__.py 8 | #rm -rf docs/html 9 | #python setup.py develop 10 | #make docs 11 | #git commit docs audiofield/__init__.py -m "Update to version v$1" 12 | git commit -a -m "Update to version v$1" 13 | git flow release finish v$1 14 | python setup.py sdist upload -r pypi 15 | 16 | 17 | 18 | git flow release start v$1 19 | sed -i -e "s/__version__ = '.*'/__version__ = '$1'/g" audiofield/__init__.py 20 | 21 | #make docs 22 | #git commit docs audiofield/__init__.py -m "Update to version v$1" 23 | git commit -a -m "Update to version v$1" 24 | git flow release finish v$1 25 | # python setup.py sdist upload -r pypi 26 | python setup.py sdist 27 | twine upload dist/django-audiofield-$1.tar.gz 28 | git push origin develop; git push origin master; git push --tag 29 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | django-audiofield 4 | 5 | Copyright (c) 2011-2014 Arezqui Belaid and other contributors 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /audiofield/middleware/threadlocals.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | 14 | import threading 15 | 16 | _thread_locals = threading.local() 17 | 18 | 19 | def get_current_request(): 20 | return getattr(_thread_locals, 'request', None) 21 | 22 | 23 | class ThreadLocals(object): 24 | """ 25 | Middleware that gets various objects from the 26 | request object and saves them in thread local storage. 27 | """ 28 | 29 | def __init__(self, get_response=None): 30 | self.get_response = get_response 31 | 32 | def __call__(self, request): 33 | response = None 34 | if hasattr(self, 'process_request'): 35 | response = self.process_request(request) 36 | if not response: 37 | response = self.get_response(request) 38 | if hasattr(self, 'process_response'): 39 | response = self.process_response(request, response) 40 | return response 41 | 42 | def process_request(self, request): 43 | _thread_locals.request = request 44 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # coding=utf-8 3 | 4 | try: 5 | from setuptools import setup 6 | except ImportError: 7 | from distutils.core import setup 8 | 9 | import os 10 | import audiofield 11 | 12 | 13 | def read(*parts): 14 | return open(os.path.join(os.path.dirname(__file__), *parts)).read() 15 | 16 | 17 | setup( 18 | name='django-audiofield', 19 | version=audiofield.__version__, 20 | description='Django application to upload and convert audio files (mp3, wav and ogg format)', 21 | long_description=read('README.rst'), 22 | url='http://github.com/Star2Billing/django-audiofield', 23 | author='Belaid Arezqui', 24 | author_email='areski@gmail.com', 25 | license='MIT License', 26 | zip_safe=False, 27 | packages=[ 28 | 'audiofield', 29 | ], 30 | include_package_data=True, 31 | package_data={}, 32 | install_requires=[ 33 | 'celery>=3.1.7', 34 | 'django-celery>=3.1.1', 35 | 'six>=1.9', 36 | # -*- Extra requirements: -*- 37 | ], 38 | classifiers=[ 39 | 'Development Status :: 5 - Production/Stable', 40 | 'Environment :: Web Environment', 41 | 'Framework :: Django', 42 | 'Intended Audience :: Developers', 43 | 'License :: OSI Approved :: MIT License', 44 | 'Operating System :: OS Independent', 45 | 'Programming Language :: Python', 46 | 'Topic :: Software Development :: Libraries :: Python Modules' 47 | ], 48 | ) 49 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/flashblock/basic.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | SoundManager 2: Flash blocker handling - basic example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | 26 |
27 | 28 |

SoundManager 2: Flashblock / "click to flash" handling: Basic Demo

29 | 30 |
31 | 32 |
33 | 34 |

See flashblock.css as a template for making your own SM2 + flash block implementations.

35 | 36 |
37 | -------------------------------------------------------------------------------- /audiofield/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9 on 2015-12-15 14:46 3 | from __future__ import unicode_literals 4 | 5 | import audiofield.fields 6 | from django.conf import settings 7 | from django.db import migrations, models 8 | import django.db.models.deletion 9 | 10 | 11 | class Migration(migrations.Migration): 12 | 13 | initial = True 14 | 15 | dependencies = [ 16 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 17 | ] 18 | 19 | operations = [ 20 | migrations.CreateModel( 21 | name='AudioFile', 22 | fields=[ 23 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 24 | ('name', models.CharField(help_text='audio file label', max_length=150, verbose_name='audio name')), 25 | ('audio_file', audiofield.fields.AudioField(blank=True, upload_to=b'upload/audiofiles', verbose_name='audio file')), 26 | ('created_date', models.DateTimeField(auto_now_add=True)), 27 | ('updated_date', models.DateTimeField(auto_now=True)), 28 | ('user', models.ForeignKey(help_text='select user', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')), 29 | ], 30 | options={ 31 | 'db_table': 'audio_file', 32 | 'verbose_name': 'audio file', 33 | 'verbose_name_plural': 'audio files', 34 | 'permissions': (('view_audiofile', 'can see Audio Files'),), 35 | }, 36 | ), 37 | ] 38 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/flashblock/method1/flashblock.css: -------------------------------------------------------------------------------- 1 | #sm2-container { 2 | /* where the SM2 flash movie goes. */ 3 | position:relative; 4 | } 5 | 6 | #sm2-container, 7 | #sm2-container embed, 8 | #sm2-container.swf_timedout { 9 | /* 48px square flash placeholder is typically used by blockers */ 10 | width:48px; 11 | height:48px; 12 | } 13 | 14 | #sm2-container.swf_timedout { 15 | /* likely a flash block situation. Maybe make it more bold, red, show descriptive nested elements? */ 16 | border:1px solid red; 17 | } 18 | 19 | #sm2-container object, 20 | #sm2-container embed { 21 | /* hide flash off-screen by default */ 22 | position:absolute; 23 | left:-9999em; 24 | top:-9999em; 25 | } 26 | 27 | #sm2-container.swf_timedout object, 28 | #sm2-container.swf_timedout embed { 29 | /* when blocked, make visible inside container */ 30 | left:auto; 31 | top:auto; 32 | } 33 | 34 | #sm2-container object, 35 | #sm2-container embed { 36 | /* 6x6 is small enough to be "invisible" and not blocked by click2flash if allowed, also enough to be really fast/performant on-screen */ 37 | width:48px; 38 | height:48px; 39 | } 40 | 41 | #sm2-container.swf_unblocked, 42 | #sm2-container.swf_unblocked object, 43 | #sm2-container.swf_unblocked embed { 44 | width:6px; 45 | height:6px; 46 | } 47 | 48 | #sm2-container.high_performance { 49 | position:absolute; 50 | position:fixed; 51 | _top:0px; /* IE 6 hax */ 52 | bottom:0px; 53 | left:0px; 54 | } 55 | 56 | #sm2-container.high_performance object, 57 | #sm2-container.high_performance embed { 58 | position:absolute; 59 | left:0px; 60 | top:0px; 61 | } -------------------------------------------------------------------------------- /audiofield/forms.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | from django import forms 14 | from django.forms.fields import FileField 15 | from django.forms import ModelForm 16 | from audiofield.models import AudioFile 17 | from audiofield.widgets import CustomerAudioFileWidget 18 | 19 | 20 | class AudioFormField(FileField): 21 | """ 22 | Field Class to upload audio file 23 | """ 24 | def clean(self, data, initial=None): 25 | if data != '__deleted__': 26 | return super(AudioFormField, self).clean(data, initial) 27 | else: 28 | return '__deleted__' 29 | 30 | 31 | class AdminAudioFileForm(ModelForm): 32 | """ 33 | This form aims to be used in the django admin, support 34 | all the features for convertion per default 35 | """ 36 | class Meta: 37 | model = AudioFile 38 | fields = ['name', 'audio_file'] 39 | 40 | 41 | class CustomerAudioFileForm(ModelForm): 42 | """ 43 | The following form aims to be used on frontend to power 44 | simple upload of audio files without convertion 45 | """ 46 | audio_file = forms.FileField(widget=CustomerAudioFileWidget) 47 | 48 | class Meta: 49 | model = AudioFile 50 | fields = ['name', 'tag', 'audio_file', ] 51 | exclude = ('user',) 52 | -------------------------------------------------------------------------------- /audiofield/admin.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | 14 | from django.contrib import admin 15 | from audiofield.models import AudioFile 16 | from django.utils.translation import gettext_lazy as _ 17 | import os 18 | 19 | 20 | class AudioFileAdmin(admin.ModelAdmin): 21 | """Allows the administrator to view and modify uploaded audio files""" 22 | 23 | list_display = ('id', 'name', 'tag', 'audio_file_player', 'created_date', 'user') 24 | # list_display_links = ['id', 'name',] 25 | ordering = ('id', ) 26 | 27 | actions = ['custom_delete_selected'] 28 | 29 | def custom_delete_selected(self, request, queryset): 30 | # custom delete code 31 | n = queryset.count() 32 | for i in queryset: 33 | if i.audio_file: 34 | if os.path.exists(i.audio_file.path): 35 | os.remove(i.audio_file.path) 36 | i.delete() 37 | self.message_user(request, _("Successfully deleted %d audio files.") % n) 38 | custom_delete_selected.short_description = "Delete selected items" 39 | 40 | def get_actions(self, request): 41 | actions = super(AudioFileAdmin, self).get_actions(request) 42 | del actions['delete_selected'] 43 | return actions 44 | 45 | 46 | admin.site.register(AudioFile, AudioFileAdmin) 47 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | Nova Style Commandments 2 | ======================= 3 | 4 | Step 1: Read http://www.python.org/dev/peps/pep-0008/ 5 | Step 2: Read http://www.python.org/dev/peps/pep-0008/ again 6 | Step 3: Read on 7 | 8 | Imports 9 | ------- 10 | - thou shalt not import objects, only modules 11 | - thou shalt not import more than one module per line 12 | - thou shalt not make relative imports 13 | - thou shalt "from nova import vendor" before importing third party code 14 | - thou shalt organize your imports according to the following template 15 | 16 | :: 17 | # vim: tabstop=4 shiftwidth=4 softtabstop=4 18 | {{stdlib imports in human alphabetical order}} 19 | \n 20 | from nova import vendor 21 | {{vendor imports in human alphabetical order}} 22 | \n 23 | {{nova imports in human alphabetical order}} 24 | \n 25 | \n 26 | {{begin your code}} 27 | 28 | 29 | General 30 | ------- 31 | - thou shalt put two newlines twixt toplevel code (funcs, classes, etc) 32 | - thou shalt put one newline twixt methods in classes and anywhere else 33 | - thou shalt not write "except:", use "except Exception:" at the very least 34 | - thou shalt include your name with TODOs as in "TODO(termie)" 35 | - thou shalt not name anything the same name as a builtin or reserved word 36 | - thou shalt not violate causality in our time cone, or else 37 | 38 | 39 | Human Alphabetical Order Examples 40 | --------------------------------- 41 | :: 42 | import httplib 43 | import logging 44 | import random 45 | import StringIO 46 | import time 47 | import unittest 48 | 49 | 50 | 51 | Tool to make code PEP8 compliant 52 | -------------------------------- 53 | - Install : https://github.com/cburroughs/pep8 54 | - Usage in your project directory : pep8 --statistics --filename=*.py --show-source --show-pep8 . 55 | 56 | -------------------------------------------------------------------------------- /audiofield/tests.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | 14 | from django.contrib.auth.models import User 15 | from django.test import TestCase 16 | from common.utils import BaseAuthenticatedClient 17 | from audiofield.models import AudioFile 18 | from audiofield.forms import CustomerAudioFileForm 19 | 20 | 21 | class AudiofieldAdminInterfaceTestCase(BaseAuthenticatedClient): 22 | """Test cases for Audiofield Admin Interface.""" 23 | 24 | def test_admin_audiofile_list(self): 25 | """Test Function to check admin audio file list""" 26 | response = self.client.get('/admin/audiofield/audiofile/') 27 | self.failUnlessEqual(response.status_code, 200) 28 | 29 | def test_admin_audiofile_add(self): 30 | """Test Function to check admin audio file add""" 31 | response = self.client.get('/admin/audiofield/audiofile/add/') 32 | self.failUnlessEqual(response.status_code, 200) 33 | 34 | 35 | class AudioFileModel(TestCase): 36 | """Test AudioFile model""" 37 | 38 | fixtures = ['auth_user.json'] 39 | 40 | def setUp(self): 41 | self.user = User.objects.get(username='admin') 42 | self.audiofile = AudioFile( 43 | name='MyAudio', 44 | tag='TAG01', 45 | user=self.user, 46 | ) 47 | self.audiofile.save() 48 | 49 | def test_name(self): 50 | self.assertEqual(self.audiofile.name, "MyAudio") 51 | 52 | def test_audio_form(self): 53 | form = CustomerAudioFileForm(instance=self.audiofile) 54 | 55 | self.assertTrue(isinstance(form.instance, AudioFile)) 56 | self.assertEqual(form.instance.pk, self.audiofile.pk) 57 | 58 | def teardown(self): 59 | self.audiofile.delete() 60 | -------------------------------------------------------------------------------- /docs/source/installation-overview.rst: -------------------------------------------------------------------------------- 1 | .. _installation-overview: 2 | 3 | ===================== 4 | Installation overview 5 | ===================== 6 | 7 | .. _install-requirements: 8 | 9 | Install requirements 10 | ==================== 11 | 12 | A requirements file stores a list of dependencies to be installed for your project/application. 13 | 14 | To get started with Django-audiofield you must have the following installed: 15 | 16 | - python >= 2.4 (programming language) 17 | - Apache / http server with WSGI modules 18 | - Django Framework >= 1.3 (Python based Web framework) 19 | - Django-uuidfield 20 | 21 | 22 | .. _install_dependencies: 23 | 24 | Install dependencies 25 | ==================== 26 | 27 | Install dependencies on Debian:: 28 | 29 | apt-get -y install libsox-fmt-mp3 libsox-fmt-all mpg321 ffmpeg 30 | 31 | 32 | Install dependencies on Redhat/CentOS:: 33 | 34 | yum -y install python-setuptools libsox-fmt-mp3 libsox-fmt-all mpg321 ffmpeg 35 | 36 | 37 | .. _install_requirements: 38 | 39 | Install requirements 40 | ==================== 41 | 42 | Use PIP to install the dependencies listed in the requirements file,:: 43 | 44 | $ pip install -r requirements.txt 45 | 46 | 47 | .. _configuration: 48 | 49 | Configuration 50 | ============= 51 | 52 | Add ``audiofield`` into INSTALLED_APPS in settings.py:: 53 | 54 | INSTALLED_APPS = ( 55 | ... 56 | 'audiofield', 57 | ...) 58 | 59 | Add the following code to your middleware:: 60 | 61 | MIDDLEWARE_CLASSES = ( 62 | ... 63 | 'audiofield.middleware.threadlocals.ThreadLocals', 64 | ) 65 | 66 | If you are going to add customer audio form on your frontend, please add following:: 67 | 68 | # Frontend widget values 69 | CHANNEL_TYPE_VALUE = 0 # 0-Keep original, 1-Mono, 2-Stereo 70 | 71 | FREQ_TYPE_VALUE = 8000 # 0-Keep original, 8000-8000Hz, 16000-16000Hz, 22050-22050Hz, 72 | # 44100-44100Hz, 48000-48000Hz, 96000-96000Hz 73 | 74 | CONVERT_TYPE_VALUE = 0 # 0-Keep original, 1-Convert to MP3, 2-Convert to WAV, 3-Convert to OGG 75 | 76 | Run following commands:: 77 | 78 | python manage.py syncdb 79 | 80 | python manage.py collectstatic 81 | 82 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | 0.9.1 (2017-04-04) 5 | ------------------ 6 | 7 | * Remove Flash player & use HTML5 Audio 8 | 9 | 10 | 0.9.0 (2017-03-06) 11 | ------------------ 12 | 13 | * Remove intermediate models 14 | 15 | 16 | 0.8.3 (2016-06-20) 17 | ------------------ 18 | 19 | * Use remix - to convert wav with c2 to c1" 20 | 21 | 22 | 0.8.2 (2016-03-01) 23 | ------------------ 24 | 25 | * Bypass the conversion through a bash script 26 | 27 | 28 | 0.8.1 (2016-01-12) 29 | ------------------ 30 | 31 | * Fixed MP3 Stereo remix 32 | 33 | 34 | 0.8.0 (2016-01-12) 35 | ------------------ 36 | 37 | * Remix when 2 channels detected 38 | * Improvement setup.py 39 | 40 | 41 | 0.7.0 (2015-12-15) 42 | ------------------ 43 | 44 | * Add migrations for Django>=1.8 support 45 | 46 | 47 | 0.6.2 (2014-05-28) 48 | ------------------ 49 | 50 | * Update to include south support 51 | 52 | 53 | 0.6.1 (2014-02-07) 54 | ------------------ 55 | 56 | * Remove audio files samples 57 | 58 | 59 | 0.6.0 (2014-02-07) 60 | ------------------ 61 | 62 | * Pin the requirement / remove django-uuidfield 63 | * Update setup.py / move requirement to root / rename changelog file 64 | 65 | 66 | 0.5.9 (2014-02-05) 67 | ------------------ 68 | 69 | * Reduce dependencies to django-lets-go 70 | 71 | 72 | 0.5.8 (2013-10-26) 73 | ------------------ 74 | 75 | * Fix convertions to OGG 76 | * Update install instructions 77 | 78 | 79 | 0.5.7 (2013-10-25) 80 | ------------------ 81 | 82 | * Fix convertion from MP3 to WAV and from OGG to WAV 83 | 84 | 85 | 0.5.6 (2013-10-24) 86 | ------------------ 87 | 88 | * Change permission name to view_audiofile 89 | 90 | 91 | 0.5.5 (2013-03-07) 92 | ------------------ 93 | 94 | * Update trans string 95 | 96 | 97 | 0.5.4 (2012-12-05) 98 | ------------------ 99 | 100 | * Fix sox conversion 101 | 102 | 103 | 0.5.3 (2012-12-04) 104 | ------------------ 105 | 106 | * Replace commands by subprocess 107 | 108 | 109 | 0.5.2 (2012-10-16) 110 | ------------------ 111 | 112 | * Add celery requirements 113 | 114 | 115 | 0.5 (2012-10-04) 116 | ------------------ 117 | 118 | * Fix requirements 119 | 120 | 121 | 0.4 (2012-10-03) 122 | ------------------ 123 | 124 | * Improve setup.py and update manifest 125 | * Update README.rst 126 | * Fix PEP8 127 | 128 | 129 | 0.3 (2011-12-09) 130 | ---------------- 131 | 132 | * Import project 133 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/css/demo.css: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------- 3 | In-page demo CSS for code, documentation etc. 4 | See page-player.css for actual playlist-relevant stuff. 5 | ----------------------------------------------------------------- 6 | */ 7 | 8 | #soundmanager-debug { 9 | /* SM2 debug container (optional, makes debug more useable) */ 10 | position:absolute;position:fixed;*position:absolute;bottom:10px;right:10px;width:50em;height:18em;overflow:auto;background:#fff;margin:1em;padding:1em;border:1px solid #999;font-family:"lucida console",verdana,tahoma,"sans serif";font-size:x-small;line-height:1.5em;opacity:0.9;filter:alpha(opacity=90);z-index:99; 11 | } 12 | 13 | body { 14 | font:75% normal verdana,arial,tahoma,"sans serif"; 15 | } 16 | 17 | h1, h2, h3 { 18 | font:300 3em "Helvetica Neue",georgia,"times new roman","Arial Rounded MT Bold",helvetica,verdana,tahoma,arial,"sans serif"; 19 | margin-bottom:0px; 20 | } 21 | 22 | h1, h2 { 23 | letter-spacing:-1px; /* zomg web x.0! ;) */ 24 | } 25 | 26 | h1, h2, h3 { 27 | float:left; 28 | clear:both; 29 | border-bottom:1px solid #999; 30 | padding-bottom:1px; 31 | margin-bottom:0.25em; 32 | } 33 | 34 | h1 { 35 | margin-top:0px; 36 | margin-bottom:0px; 37 | background-color:#666; 38 | color:#ccc; 39 | margin-left:-5px; 40 | padding-left:5px; 41 | padding-right:5px; 42 | } 43 | 44 | h1, 45 | h1 a { 46 | color:#fff; 47 | text-decoration:none; 48 | } 49 | 50 | h1 a:hover { 51 | text-decoration:underline; 52 | } 53 | 54 | h2 { 55 | font-size:2em; 56 | margin-top:1em; 57 | background-color:#aaa; 58 | color:#fff; 59 | padding:5px; 60 | margin-left:-5px; 61 | min-width:23em; 62 | } 63 | 64 | h3 { 65 | font-size:1.65em; 66 | margin-top:0.5em; 67 | margin-bottom:0.25em; 68 | color:#333; 69 | min-width:28em; 70 | } 71 | 72 | h3 a { 73 | font-size:small; 74 | } 75 | 76 | h4 { 77 | color:#444; 78 | } 79 | 80 | ul.notes { 81 | margin-left:0px; 82 | padding-left:1.5em; 83 | } 84 | 85 | .note { 86 | margin-top:0px; 87 | font-style:italic; 88 | color:#999; 89 | } 90 | 91 | pre { 92 | font-size:1.2em; 93 | _font-size:1em; 94 | } 95 | 96 | code { 97 | font-family:"lucida console",monaco,courier,system; 98 | font-size:1em; 99 | color:#003366; 100 | } 101 | 102 | code span { 103 | color:#666; 104 | } 105 | 106 | ul, 107 | p, 108 | pre { 109 | clear:left; 110 | max-width:46em; 111 | } 112 | 113 | ul.tight li { 114 | max-width:44.5em; 115 | } 116 | 117 | ul.playlist { 118 | /* undo the above nonsense */ 119 | max-width:none; 120 | } 121 | 122 | ul.tight { 123 | padding-left:1.5em; 124 | } 125 | -------------------------------------------------------------------------------- /audiofield/templates/common_audiofield.html: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 47 | 48 | 49 | 58 | -------------------------------------------------------------------------------- /audiofield/tasks.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | 14 | from celery.utils.log import get_task_logger 15 | from celery.decorators import task 16 | import subprocess 17 | import os 18 | from uuid import uuid1 19 | # import shlex 20 | 21 | logger = get_task_logger(__name__) 22 | 23 | DELAY_TASK = 5 # Seconds 24 | 25 | 26 | @task() 27 | def audio_convert_task(conv): 28 | """Convert audio files""" 29 | 30 | logger.info('[audio_convert_task] Received a request to convert audio file in %dsecs' % DELAY_TASK) 31 | run_convert_task.apply_async((conv,), countdown=DELAY_TASK) 32 | 33 | return True 34 | 35 | 36 | @task() 37 | def run_convert_task(conv): 38 | """ 39 | Exec the audio convert 40 | This version use Bash to convert the audio as calling Sox directly fails 41 | """ 42 | filebash = "/tmp/bash-%s.sh" % str(uuid1()) 43 | 44 | logger.warning('Convert audio file :> %s' % str(conv)) 45 | logger.warning('Filebash :> %s' % filebash) 46 | 47 | filename = conv.split(' ')[1].strip() 48 | if os.path.isfile(filename): 49 | logger.debug("File exists!") 50 | else: 51 | logger.error("Error: File don't exist!") 52 | return False 53 | 54 | with open(filebash, 'w') as mfile: 55 | mfile.write('#!/bin/bash\n') 56 | mfile.write(conv) 57 | mfile.write('\n') 58 | 59 | cmd = [ 60 | 'bash', 61 | filebash 62 | ] 63 | 64 | # output = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0].decode("utf-8") 65 | response = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 66 | (output, error) = response.communicate() 67 | if error: 68 | logger.error('Error conversion : %s ' % error) 69 | 70 | return response 71 | 72 | 73 | @task() 74 | def old_run_convert_task(conv): 75 | """Exec the audio convert""" 76 | 77 | logger.warning('Convert audio file :> %s' % str(conv)) 78 | 79 | filename = conv.split(' ')[1].strip() 80 | if os.path.isfile(filename): 81 | logger.debug("File exists!") 82 | else: 83 | logger.error("Error: File don't exist!") 84 | 85 | # Option 1 : Popen 86 | response = subprocess.Popen(conv.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 87 | (output, error) = response.communicate() 88 | if error: 89 | logger.error('Conv :') 90 | logger.error(conv.split(' ')) 91 | logger.error('Error conversion2 : %s ' % error) 92 | 93 | # Option 2 : Popen & Shlex 94 | # args = shlex.split(conv) 95 | # p = subprocess.Popen(args) 96 | 97 | return response 98 | -------------------------------------------------------------------------------- /audiofield/models.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | from __future__ import unicode_literals 14 | 15 | import six 16 | from django.db import models 17 | from django.utils.translation import gettext_lazy as _ 18 | from django.conf import settings 19 | from audiofield.fields import AudioField 20 | 21 | try: 22 | from django.contrib.auth import get_user_model 23 | User = settings.AUTH_USER_MODEL 24 | except ImportError: 25 | from django.contrib.auth.models import User 26 | 27 | 28 | @six.python_2_unicode_compatible 29 | class AudioFile(models.Model): 30 | """ 31 | This Model describe the Audio used on the platform, 32 | this allow to upload audio file and configure 33 | alternate Text2Speech System 34 | """ 35 | name = models.CharField(max_length=150, blank=False, verbose_name=_('audio name'), 36 | help_text=_('audio file label')) 37 | audio_file = AudioField(upload_to='upload/audiofiles', blank=True, 38 | ext_whitelist=('.mp3', '.wav', '.ogg'), 39 | verbose_name=_('audio file')) 40 | user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_('user'), 41 | help_text=_('select user')) 42 | tag = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('tag'), 43 | help_text=_('tag used to categorize the audio files')) 44 | created_date = models.DateTimeField(auto_now_add=True) 45 | updated_date = models.DateTimeField(auto_now=True) 46 | 47 | class Meta: 48 | permissions = ( 49 | ('can_view_audiofile', _('can see Audio Files')), 50 | ) 51 | db_table = 'audio_file' 52 | verbose_name = _('audio file') 53 | verbose_name_plural = _('audio files') 54 | 55 | def __str__(self): 56 | return '[%s] %s' % (self.id, self.name) 57 | 58 | def save(self, force_insert=False, force_update=False, using=None, update_fields=None): 59 | # Call the "real" save() method 60 | super(AudioFile, self).save(force_insert, force_update, using, update_fields) 61 | 62 | def audio_file_player(self): 63 | """audio player tag for admin""" 64 | if self.audio_file: 65 | file_url = settings.MEDIA_URL + str(self.audio_file) 66 | player_string = '' % \ 67 | (file_url) 68 | return player_string 69 | 70 | audio_file_player.allow_tags = True 71 | audio_file_player.short_description = _('audio file player') 72 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/flashblock/method1/flashblock.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | FlashBlock handler for SoundManager 2 4 | ------------------------------------------------------------------- 5 | Attempt to handle and gracefully recover from flashblock conditions 6 | Requires SoundManger v2.95a.20090717+ 7 | 8 | http://schillmania.com/projects/soundmanager2/ 9 | 10 | */ 11 | soundManager._flashBlock = new function() { 12 | 13 | var _s = this; 14 | this.name = 'soundManager._flashblock'; 15 | this.didTimeout = false; // did initial attempt fail? 16 | this.timer = null; // for setTimeout call 17 | 18 | this.startTimer = function(nMsec) { 19 | // soundManager._wD(_s.name+'_.starttimer()'); 20 | _s.timer = window.setTimeout(_s.checkFlashStatus,nMsec); 21 | }; 22 | 23 | this.stopTimer = function() { 24 | // soundManager._wD(_s.name+'.stoptimer()'); 25 | if (_s.timer) { 26 | window.clearTimeout(_s.timer); 27 | _s.timer = null; 28 | } 29 | }; 30 | 31 | this.checkFlashStatus = function() { 32 | // soundManager._wD(_s.name+'.checkflashstatus()'); 33 | var _sm = soundManager; 34 | var oMC = _sm.oMC; // DIV (default: #sm2-container) for .SWF 35 | var oStatus = document.getElementById('sm2-status'); // demo-only 36 | 37 | if (!_sm.ok()) { 38 | // make the movie more visible, so user can fix 39 | oMC.className = 'swf-timedout'; 40 | _s.didTimeout = true; 41 | var msg = 'No flash response, applying .swf-timedout CSS..'; 42 | _sm._wD(_s.name+': '+msg); 43 | if (oStatus) { 44 | oStatus.innerHTML = ''+msg+''; 45 | } 46 | } else { 47 | // SM2 loaded OK 48 | // move the movie container to its proper place 49 | oMC.className = 'swf-loaded'; 50 | if (!_s.didTimeout) { 51 | // SM2 didn't previously fail, no blocker active 52 | var msg = 'SM2 loaded OK (before timeout), fast unblock or no blocker.'; 53 | _sm._writeDebug(_s.name+'.checkFlashStatus: '+msg,1); 54 | if (oStatus) { 55 | oStatus.innerHTML = ''+msg+''; 56 | } 57 | } else { 58 | var msg = 'SM2 recovered after block (or timeout), loaded OK.'; 59 | _sm._wD(_s.name+': '+msg); 60 | if (oStatus) { 61 | oStatus.innerHTML = ''+msg+''; 62 | } 63 | } 64 | // stop timer, if applicable 65 | _s.stopTimer(); 66 | return false; 67 | } 68 | }; 69 | 70 | soundManager.flashLoadTimeout = 0; // wait forever for flash to load - we'll set our own timeout via oninitmovie() 71 | 72 | soundManager.oninitmovie = function() { 73 | // when SWF is written (or ready to start), wait and make SWF visible (time-out case) 74 | soundManager._flashBlock.startTimer(750); 75 | }; 76 | 77 | soundManager.onready(function() { 78 | // SM2 has now initialized, either no blocking OR blocked movie was allowed/whitelisted 79 | var fb = soundManager._flashBlock; 80 | // Yay! recovered OK. 81 | fb.checkFlashStatus(); 82 | }); 83 | 84 | soundManager.ontimeout(function() { 85 | // Blocking was passed (or no blocking), but then something *else* went wrong. 86 | // stop timer, if applicable 87 | fb.stopTimer(); 88 | }); 89 | 90 | }(); 91 | -------------------------------------------------------------------------------- /docs/source/developer-doc/form.rst: -------------------------------------------------------------------------------- 1 | .. _forms: 2 | 3 | AudioFile Forms 4 | =============== 5 | 6 | .. _Audiofile_Forms: 7 | 8 | Forms Definition 9 | ---------------- 10 | 11 | This form aims to be used in the django admin, support all the features for convertion per default:: 12 | 13 | class AdminAudioFileForm(ModelForm): 14 | class Meta: 15 | model = AudioFile 16 | fields = ['name', 'audio_file'] 17 | 18 | The following form aims to be used on frontend to power simple upload of audio files without convertion:: 19 | 20 | class CustomerAudioFileForm(ModelForm): 21 | audio_file = forms.FileField(widget=CustomerAudioFileWidget) 22 | class Meta: 23 | model = AudioFile 24 | fields = ['name', 'audio_file'] 25 | exclude = ('user',) 26 | 27 | 28 | Forms Usage 29 | ----------- 30 | 31 | We provide you a simple example of using the forms to list and upload audio file on the frontend. 32 | 33 | In url.py:: 34 | 35 | ... 36 | (r'^$', 'frontend.views.add_audio'), 37 | 38 | In view.py:: 39 | 40 | ... 41 | @login_required 42 | def add_audio(request): 43 | template = 'frontend/add_audio.html' 44 | form = CustomerAudioFileForm() 45 | 46 | # Add audio 47 | if request.method == 'POST': 48 | form = CustomerAudioFileForm(request.POST, request.FILES) 49 | if form.is_valid(): 50 | obj = form.save(commit=False) 51 | obj.user = User.objects.get(username=request.user) 52 | obj.save() 53 | return HttpResponseRedirect('/') 54 | 55 | # To retain frontend widget, if form.is_valid() == False 56 | form.fields['audio_file'].widget = CustomerAudioFileWidget() 57 | 58 | data = { 59 | 'audio_form': form, 60 | } 61 | 62 | return render_to_response(template, data, 63 | context_instance=RequestContext(request)) 64 | 65 | 66 | 67 | This is an other example how to edit the audiofield on the frontend. 68 | 69 | In url.py:: 70 | 71 | ... 72 | (r'^edit/(.+)/$', 'frontend.views.edit_audio'), 73 | 74 | 75 | In view.py:: 76 | 77 | ... 78 | @login_required 79 | def edit_audio(request, object_id): 80 | 81 | obj = AudioFile.objects.get(pk=object_id) 82 | form = CustomerAudioFileForm(instance=obj) 83 | 84 | if request.GET.get('delete'): 85 | # perform delete 86 | if obj.audio_file: 87 | if os.path.exists(obj.audio_file.path): 88 | os.remove(obj.audio_file.path) 89 | obj.delete() 90 | return HttpResponseRedirect('/') 91 | 92 | if request.method == 'POST': 93 | form = CustomerAudioFileForm(request.POST, request.FILES, instance=obj) 94 | if form.is_valid(): 95 | form.save() 96 | return HttpResponseRedirect('/') 97 | 98 | template = 'frontend/edit_audio.html' 99 | 100 | data = { 101 | 'audio_form': form, 102 | } 103 | 104 | return render_to_response(template, data, 105 | context_instance=RequestContext(request)) 106 | 107 | -------------------------------------------------------------------------------- /audiofield/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Django-Audiofield\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2018-01-21 11:38+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: Belaid Arezqui \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: audiofield/admin.py:37 21 | #, python-format 22 | msgid "Successfully deleted %d audio files." 23 | msgstr "" 24 | 25 | #: audiofield/fields.py:87 26 | msgid "not allowed filetype!" 27 | msgstr "" 28 | 29 | #: audiofield/fields.py:94 30 | msgid "" 31 | "not allowed : file format conversion is not allowed for same audio type " 32 | "(except Wav)" 33 | msgstr "" 34 | 35 | #: audiofield/models.py:35 36 | msgid "audio name" 37 | msgstr "" 38 | 39 | #: audiofield/models.py:36 40 | msgid "audio file label" 41 | msgstr "" 42 | 43 | #: audiofield/models.py:39 audiofield/models.py:50 44 | msgid "audio file" 45 | msgstr "" 46 | 47 | #: audiofield/models.py:40 48 | msgid "user" 49 | msgstr "" 50 | 51 | #: audiofield/models.py:41 52 | msgid "select user" 53 | msgstr "" 54 | 55 | #: audiofield/models.py:47 56 | msgid "can see Audio Files" 57 | msgstr "" 58 | 59 | #: audiofield/models.py:51 60 | msgid "audio files" 61 | msgstr "" 62 | 63 | #: audiofield/models.py:69 64 | msgid "audio file player" 65 | msgstr "" 66 | 67 | #: audiofield/widgets.py:24 audiofield/widgets.py:30 68 | msgid "Keep original" 69 | msgstr "" 70 | 71 | #: audiofield/widgets.py:25 72 | msgid "Mono" 73 | msgstr "" 74 | 75 | #: audiofield/widgets.py:26 76 | msgid "Stereo" 77 | msgstr "" 78 | 79 | #: audiofield/widgets.py:31 80 | msgid "8000 Hz" 81 | msgstr "" 82 | 83 | #: audiofield/widgets.py:32 84 | msgid "16000 Hz" 85 | msgstr "" 86 | 87 | #: audiofield/widgets.py:33 88 | msgid "22050 Hz" 89 | msgstr "" 90 | 91 | #: audiofield/widgets.py:34 92 | msgid "44100 Hz" 93 | msgstr "" 94 | 95 | #: audiofield/widgets.py:35 96 | msgid "48000 Hz" 97 | msgstr "" 98 | 99 | #: audiofield/widgets.py:39 100 | msgid "Keep original audio file" 101 | msgstr "" 102 | 103 | #: audiofield/widgets.py:40 104 | msgid "Convert to MP3" 105 | msgstr "" 106 | 107 | #: audiofield/widgets.py:41 108 | msgid "Convert to WAV" 109 | msgstr "" 110 | 111 | #: audiofield/widgets.py:42 112 | msgid "Convert to OGG" 113 | msgstr "" 114 | 115 | #: audiofield/widgets.py:79 116 | msgid "Allowed format - mp3 wav and ogg" 117 | msgstr "" 118 | 119 | #: audiofield/widgets.py:83 audiofield/widgets.py:141 120 | msgid "Currently:" 121 | msgstr "" 122 | 123 | #: audiofield/widgets.py:85 audiofield/widgets.py:143 124 | msgid "Change:" 125 | msgstr "" 126 | 127 | #: audiofield/widgets.py:87 128 | msgid "Upload:" 129 | msgstr "" 130 | 131 | #: audiofield/widgets.py:89 132 | msgid "Convert to:" 133 | msgstr "" 134 | 135 | #: audiofield/widgets.py:90 136 | msgid "Channel:" 137 | msgstr "" 138 | 139 | #: audiofield/widgets.py:91 140 | msgid "Frequency:" 141 | msgstr "" 142 | 143 | #: audiofield/widgets.py:95 144 | msgid "Delete:" 145 | msgstr "" 146 | 147 | #: audiofield/widgets.py:133 148 | msgid "Allowed format - mp3, wav and ogg" 149 | msgstr "" 150 | -------------------------------------------------------------------------------- /audiofield/locale/zh/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Django-Audiofield\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2018-01-21 11:39+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: Belaid Arezqui \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: audiofield/admin.py:37 21 | #, python-format 22 | msgid "Successfully deleted %d audio files." 23 | msgstr "成功的刪除 %d 語音檔案." 24 | 25 | #: audiofield/fields.py:87 26 | msgid "not allowed filetype!" 27 | msgstr "" 28 | 29 | #: audiofield/fields.py:94 30 | msgid "" 31 | "not allowed : file format conversion is not allowed for same audio type " 32 | "(except Wav)" 33 | msgstr "" 34 | 35 | #: audiofield/models.py:35 36 | #, fuzzy 37 | #| msgid "Audio Name" 38 | msgid "audio name" 39 | msgstr "語音檔案名稱" 40 | 41 | #: audiofield/models.py:36 42 | #, fuzzy 43 | #| msgid "Audio file label" 44 | msgid "audio file label" 45 | msgstr "語音檔案標籤" 46 | 47 | #: audiofield/models.py:39 audiofield/models.py:50 48 | #, fuzzy 49 | #| msgid "Audio file" 50 | msgid "audio file" 51 | msgstr "語音檔案" 52 | 53 | #: audiofield/models.py:40 54 | msgid "user" 55 | msgstr "" 56 | 57 | #: audiofield/models.py:41 58 | #, fuzzy 59 | #| msgid "Select User" 60 | msgid "select user" 61 | msgstr "選擇使用者" 62 | 63 | #: audiofield/models.py:47 64 | #, fuzzy 65 | #| msgid "Audio files" 66 | msgid "can see Audio Files" 67 | msgstr "語音檔案" 68 | 69 | #: audiofield/models.py:51 70 | #, fuzzy 71 | #| msgid "Audio files" 72 | msgid "audio files" 73 | msgstr "語音檔案" 74 | 75 | #: audiofield/models.py:69 76 | #, fuzzy 77 | #| msgid "Audio file player" 78 | msgid "audio file player" 79 | msgstr "語音檔案撥放" 80 | 81 | #: audiofield/widgets.py:24 audiofield/widgets.py:30 82 | msgid "Keep original" 83 | msgstr "保留原有" 84 | 85 | #: audiofield/widgets.py:25 86 | msgid "Mono" 87 | msgstr "單音" 88 | 89 | #: audiofield/widgets.py:26 90 | msgid "Stereo" 91 | msgstr "立體聲" 92 | 93 | #: audiofield/widgets.py:31 94 | msgid "8000 Hz" 95 | msgstr "800 Hz" 96 | 97 | #: audiofield/widgets.py:32 98 | msgid "16000 Hz" 99 | msgstr "1600 Hz" 100 | 101 | #: audiofield/widgets.py:33 102 | msgid "22050 Hz" 103 | msgstr "22050 Hz" 104 | 105 | #: audiofield/widgets.py:34 106 | msgid "44100 Hz" 107 | msgstr "44100 Hz" 108 | 109 | #: audiofield/widgets.py:35 110 | msgid "48000 Hz" 111 | msgstr "48000 Hz" 112 | 113 | #: audiofield/widgets.py:39 114 | msgid "Keep original audio file" 115 | msgstr "保留原有語音檔案" 116 | 117 | #: audiofield/widgets.py:40 118 | msgid "Convert to MP3" 119 | msgstr "轉成 MP3" 120 | 121 | #: audiofield/widgets.py:41 122 | msgid "Convert to WAV" 123 | msgstr "轉成 WAV" 124 | 125 | #: audiofield/widgets.py:42 126 | msgid "Convert to OGG" 127 | msgstr "轉成 OGG" 128 | 129 | #: audiofield/widgets.py:79 130 | msgid "Allowed format - mp3 wav and ogg" 131 | msgstr "允許的格式 - mp3 wav and ogg" 132 | 133 | #: audiofield/widgets.py:83 audiofield/widgets.py:141 134 | msgid "Currently:" 135 | msgstr "現在" 136 | 137 | #: audiofield/widgets.py:85 audiofield/widgets.py:143 138 | msgid "Change:" 139 | msgstr "變更" 140 | 141 | #: audiofield/widgets.py:87 142 | msgid "Upload:" 143 | msgstr "上傳" 144 | 145 | #: audiofield/widgets.py:89 146 | #, fuzzy 147 | #| msgid "Convert To:" 148 | msgid "Convert to:" 149 | msgstr "轉成:" 150 | 151 | #: audiofield/widgets.py:90 152 | msgid "Channel:" 153 | msgstr "頻道" 154 | 155 | #: audiofield/widgets.py:91 156 | msgid "Frequency:" 157 | msgstr "頻率" 158 | 159 | #: audiofield/widgets.py:95 160 | msgid "Delete:" 161 | msgstr "刪除" 162 | 163 | #: audiofield/widgets.py:133 164 | msgid "Allowed format - mp3, wav and ogg" 165 | msgstr "允許的格式 - mp3, wav 以及ogg" 166 | 167 | #~ msgid "English" 168 | #~ msgstr "英文" 169 | 170 | #~ msgid "Spanish" 171 | #~ msgstr "西班牙文" 172 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/css/optional-annotations.css: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------ 3 | -- annotations (sub-tracks, notes etc.) -- 4 | ------------------------------------------ 5 | */ 6 | 7 | ul.playlist li a.sm2_link .metadata { 8 | display:none; /* hide by default */ 9 | } 10 | 11 | ul.playlist li.sm2_paused a.sm2_link .metadata, 12 | ul.playlist li.sm2_playing a.sm2_link .metadata { 13 | display:inline; 14 | } 15 | 16 | ul.playlist li ul { 17 | list-style-type:none; 18 | margin:0px; 19 | padding:0px; 20 | position:relative; 21 | font-size:small; 22 | display:none; 23 | } 24 | 25 | ul.playlist li ul li { 26 | position:relative; 27 | margin:0px; 28 | padding:2px 3px; 29 | border:1px solid transparent; 30 | -moz-border-radius:6px; 31 | -khtml-border-radius:6px; 32 | border-radius:6px; 33 | margin-right:1em; 34 | font-family:helvetica,verdana,tahoma,arial,"sans serif"; 35 | font-size:x-small; 36 | font-weight:300; 37 | letter-spacing:0px; 38 | background-color:transparent; 39 | opacity:0.66; 40 | } 41 | 42 | ul.playlist li ul li:hover { 43 | opacity:1; 44 | background-color:#fff; 45 | border-color:#ccc; 46 | color:#666; 47 | } 48 | 49 | ul.playlist li.sm2_playing ul li, 50 | ul.playlist li.sm2_paused ul li { 51 | color:#fff; 52 | } 53 | 54 | ul.playlist li.sm2_playing ul li:hover { 55 | background-color:#fff; 56 | color:#5588bb; 57 | border-color:#336699; 58 | opacity:0.9; 59 | } 60 | 61 | ul.playlist li.sm2_paused ul li:hover { 62 | background-color:#888; 63 | } 64 | 65 | /* metadata */ 66 | 67 | ul.playlist li .metadata .duration { 68 | /* optional timing data */ 69 | display:none; 70 | } 71 | 72 | ul.playlist li .metadata ul li p { 73 | margin:0px; 74 | padding:0px; 75 | } 76 | 77 | ul.playlist li .metadata ul li span { 78 | display:none; 79 | } 80 | 81 | ul.playlist li .controls .statusbar .annotation { 82 | position:absolute; 83 | background-color:transparent; 84 | top:0px; 85 | color:#666; 86 | text-align:right; 87 | margin-left:10px; 88 | height:0.5em; 89 | } 90 | 91 | ul.playlist li .controls .statusbar .annotation:hover { 92 | z-index:12; /* sit on top of note */ 93 | } 94 | 95 | ul.playlist li .controls .statusbar .annotation span.bubble { 96 | /* using · */ 97 | display:inline-block; 98 | background-color:#fff; 99 | border:1px solid #666; 100 | border-radius:6px; 101 | -moz-border-radius:6px; 102 | -webkit-border-radius:6px; 103 | } 104 | 105 | ul.playlist li .controls .statusbar .annotation span { 106 | display:block; 107 | background:transparent url(../image/divot.png) no-repeat 50% 0px; 108 | width:15px; 109 | margin-left:-15px; 110 | height:12px; 111 | text-align:center; 112 | } 113 | 114 | ul.playlist li .controls .statusbar .annotation.alt { 115 | top:auto; 116 | bottom:0px; 117 | } 118 | 119 | ul.playlist li .controls .statusbar .annotation span:hover { 120 | cursor:none; /* Fx3 rules. */ 121 | margin-top:0.1em; 122 | } 123 | 124 | ul.playlist li .controls .statusbar .annotation.alt span:hover { 125 | margin-top:-0.1em; 126 | } 127 | 128 | ul.playlist li .controls .statusbar .annotation.alt span { 129 | background:transparent url(../image/divot-bottom.png) no-repeat 50% bottom; 130 | } 131 | 132 | ul.playlist li .note { 133 | position:absolute; 134 | display:none; 135 | left:0px; 136 | top:0px; 137 | z-index:10; 138 | font-size:x-small; 139 | padding:2px 4px 2px 4px; 140 | width:auto; 141 | color:#666; 142 | background-color:#fff; 143 | border:1px solid #ccc; 144 | border-radius:6px; 145 | -moz-border-radius:6px; 146 | -webkit-border-radius:6px; 147 | font-style:normal; 148 | font-weight:bold; 149 | font-family:arial,tahoma,verdana,"sans serif"; 150 | letter-spacing:0px; 151 | margin-top:1.1em; 152 | } 153 | 154 | ul.playlist li .note.alt { 155 | margin-top:-1.32em; 156 | } 157 | 158 | ul.playlist li .note:hover { 159 | display:block !important; 160 | } 161 | 162 | ul.playlist li .sm2_divider { 163 | font-size:0.75em; 164 | } 165 | 166 | ul.playlist li .sm2_metadata { 167 | font-size:0.65em; 168 | } 169 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/flashblock/flashblock.css: -------------------------------------------------------------------------------- 1 | /** 2 | * SoundManager 2 + useFlashBlock 3 | * ------------------------------ 4 | * Flash positioning and flashblock / clicktoflash handling 5 | */ 6 | 7 | #sm2-container { 8 | /** 9 | * where the SM2 flash movie goes. by default, relative container. 10 | * set relative or absolute here, and don't touch it later or bad things will happen (see below comments.) 11 | */ 12 | position: absolute; 13 | width: 1px; 14 | height: 1px; 15 | overflow: hidden; 16 | /* screw IE 6, just make it display nice */ 17 | _overflow: hidden; 18 | } 19 | 20 | #sm2-container object, 21 | #sm2-container embed { 22 | /** 23 | * the actual SWF movie bit. 24 | * important: The SWF needs to be able to be moved off-screen without display: or position: changes. 25 | * changing display: or position: or overflow: here or on parent can cause SWF reload or other weird issues after unblock 26 | * e.g., SM2 starts but strange errors, no whileplaying() etc. 27 | */ 28 | width: 48px; 29 | height: 48px; 30 | /* some flash blockers may also respect this rule */ 31 | max-width: 48px; 32 | max-height: 48px; 33 | } 34 | 35 | #sm2-container.swf_timedout { 36 | /* expand to show the timed-out SWF content */ 37 | position: relative; 38 | width: 48px; 39 | height: 48px; 40 | } 41 | 42 | #sm2-container.swf_timedout, 43 | #sm2-container.swf_timedout object, 44 | #sm2-container.swf_timedout embed { 45 | /** 46 | * when SM2 didn't start normally, time-out case. flash blocked, missing SWF, no flash? 47 | * 48px square flash placeholder is typically used by blockers. 48 | */ 49 | min-width: 48px; 50 | min-height: 48px; 51 | } 52 | 53 | #sm2-container.swf_unblocked { 54 | /* SWF unblocked, or was never blocked to begin with; try to collapse container as much as possible. */ 55 | width: 1px; 56 | height: 1px; 57 | } 58 | 59 | #sm2-container.swf_loaded object, 60 | #sm2-container.swf_loaded embed, 61 | #sm2-container.swf_unblocked object, 62 | #sm2-container.swf_unblocked embed { 63 | /* hide flash off-screen (relative to container) when it has loaded OK */ 64 | left: -9999em; 65 | top: -9999em; 66 | } 67 | 68 | #sm2-container.swf_error { 69 | /* when there is a fatal error (flash loaded, but SM2 failed) */ 70 | display: none; 71 | } 72 | 73 | #sm2-container.high_performance, 74 | #sm2-container.high_performance.swf_timeout { 75 | /* "high performance" case: keep on-screen at all times */ 76 | position: absolute; 77 | position: fixed; 78 | } 79 | 80 | #sm2-container.high_performance { 81 | overflow: hidden; 82 | _top: -9999px; /* IE 6 hax, no position:fixed */ 83 | _left: -9999px; 84 | bottom: 0px; 85 | left: 0px; 86 | /** 87 | * special case: show at first with w/h, hide when unblocked. 88 | * might be bad/annoying. 89 | * try to stay within ClickToFlash "invisible" limits (so it won't be blocked.) 90 | */ 91 | z-index: 99; /* try to stay on top */ 92 | } 93 | 94 | #sm2-container.high_performance.swf_loaded, 95 | #sm2-container.high_performance.swf_unblocked { 96 | z-index: auto; 97 | } 98 | 99 | #sm2-container.high_performance.swf_loaded, 100 | #sm2-container.high_performance.swf_unblocked, 101 | #sm2-container.high_performance.swf_unblocked object, 102 | #sm2-container.high_performance.swf_unblocked embed { 103 | /** 104 | * 8x8px is required minimum to load in fx/win32 in some cases(?) 105 | * 6x6+ good for fast performance, even better when on-screen via position:fixed 106 | * also, clickToFlash (Safari <5.1) may auto-load "invisible" SWFs at this size 107 | */ 108 | height: 8px; 109 | width: 8px; 110 | } 111 | 112 | #sm2-container.high_performance.swf_loaded { 113 | /* stay bottom/left */ 114 | top: auto; 115 | bottom: 0px; 116 | left: 0px; 117 | } 118 | 119 | #sm2-container.high_performance.swf_loaded object, 120 | #sm2-container.high_performance.swf_loaded embed, 121 | #sm2-container.high_performance.swf_unblocked object, 122 | #sm2-container.high_performance.swf_unblocked embed { 123 | /* high-performance case must stay on-screen */ 124 | left: auto; 125 | top: auto; 126 | } 127 | 128 | #sm2-container.high_performance.swf_timedout { 129 | z-index: 99; /* try to stay on top */ 130 | } -------------------------------------------------------------------------------- /audiofield/locale/pt/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2018-01-21 11:39+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 20 | 21 | #: audiofield/admin.py:37 22 | #, python-format 23 | msgid "Successfully deleted %d audio files." 24 | msgstr "Excluído com sucesso arquivos %d áudio." 25 | 26 | #: audiofield/fields.py:87 27 | msgid "not allowed filetype!" 28 | msgstr "" 29 | 30 | #: audiofield/fields.py:94 31 | msgid "" 32 | "not allowed : file format conversion is not allowed for same audio type " 33 | "(except Wav)" 34 | msgstr "" 35 | 36 | #: audiofield/models.py:35 37 | #, fuzzy 38 | #| msgid "Audio Name" 39 | msgid "audio name" 40 | msgstr "Nome de áudio" 41 | 42 | #: audiofield/models.py:36 43 | #, fuzzy 44 | #| msgid "Audio file label" 45 | msgid "audio file label" 46 | msgstr "Label arquivo de áudio" 47 | 48 | #: audiofield/models.py:39 audiofield/models.py:50 49 | #, fuzzy 50 | #| msgid "Audio file" 51 | msgid "audio file" 52 | msgstr "Arquivo de áudio" 53 | 54 | #: audiofield/models.py:40 55 | msgid "user" 56 | msgstr "" 57 | 58 | #: audiofield/models.py:41 59 | #, fuzzy 60 | #| msgid "Select User" 61 | msgid "select user" 62 | msgstr "Selecione Usuário" 63 | 64 | #: audiofield/models.py:47 65 | #, fuzzy 66 | #| msgid "Audio files" 67 | msgid "can see Audio Files" 68 | msgstr "Arquivos de áudio" 69 | 70 | #: audiofield/models.py:51 71 | #, fuzzy 72 | #| msgid "Audio files" 73 | msgid "audio files" 74 | msgstr "Arquivos de áudio" 75 | 76 | #: audiofield/models.py:69 77 | #, fuzzy 78 | #| msgid "Audio file player" 79 | msgid "audio file player" 80 | msgstr "Reprodutor de arquivos de áudio" 81 | 82 | #: audiofield/widgets.py:24 audiofield/widgets.py:30 83 | msgid "Keep original" 84 | msgstr "Manter original" 85 | 86 | #: audiofield/widgets.py:25 87 | msgid "Mono" 88 | msgstr "Mono" 89 | 90 | #: audiofield/widgets.py:26 91 | msgid "Stereo" 92 | msgstr "Estéreo" 93 | 94 | #: audiofield/widgets.py:31 95 | msgid "8000 Hz" 96 | msgstr "8000 Hz" 97 | 98 | #: audiofield/widgets.py:32 99 | msgid "16000 Hz" 100 | msgstr "16000 Hz" 101 | 102 | #: audiofield/widgets.py:33 103 | msgid "22050 Hz" 104 | msgstr "22.050 Hz" 105 | 106 | #: audiofield/widgets.py:34 107 | msgid "44100 Hz" 108 | msgstr "44100 Hz" 109 | 110 | #: audiofield/widgets.py:35 111 | msgid "48000 Hz" 112 | msgstr "48000 Hz" 113 | 114 | #: audiofield/widgets.py:39 115 | msgid "Keep original audio file" 116 | msgstr "Manter arquivo de áudio original" 117 | 118 | #: audiofield/widgets.py:40 119 | msgid "Convert to MP3" 120 | msgstr "Converter para MP3" 121 | 122 | #: audiofield/widgets.py:41 123 | msgid "Convert to WAV" 124 | msgstr "Converter para WAV" 125 | 126 | #: audiofield/widgets.py:42 127 | msgid "Convert to OGG" 128 | msgstr "Converter para OGG" 129 | 130 | #: audiofield/widgets.py:79 131 | msgid "Allowed format - mp3 wav and ogg" 132 | msgstr "Formato permitido - mp3 wav e ogg" 133 | 134 | #: audiofield/widgets.py:83 audiofield/widgets.py:141 135 | msgid "Currently:" 136 | msgstr "Atualmente:" 137 | 138 | #: audiofield/widgets.py:85 audiofield/widgets.py:143 139 | msgid "Change:" 140 | msgstr "Mudança:" 141 | 142 | #: audiofield/widgets.py:87 143 | msgid "Upload:" 144 | msgstr "Upload:" 145 | 146 | #: audiofield/widgets.py:89 147 | #, fuzzy 148 | #| msgid "Convert To:" 149 | msgid "Convert to:" 150 | msgstr "Para converter:" 151 | 152 | #: audiofield/widgets.py:90 153 | msgid "Channel:" 154 | msgstr "Canal:" 155 | 156 | #: audiofield/widgets.py:91 157 | msgid "Frequency:" 158 | msgstr "Frequência:" 159 | 160 | #: audiofield/widgets.py:95 161 | msgid "Delete:" 162 | msgstr "Delete:" 163 | 164 | #: audiofield/widgets.py:133 165 | msgid "Allowed format - mp3, wav and ogg" 166 | msgstr "Formato permitido - mp3, wav e ogg" 167 | 168 | #~ msgid "English" 169 | #~ msgstr "Inglês" 170 | 171 | #~ msgid "Spanish" 172 | #~ msgstr "Espanhol" 173 | 174 | #~ msgid "Portuguese" 175 | #~ msgstr "Português" 176 | -------------------------------------------------------------------------------- /audiofield/locale/es/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2018-01-21 11:39+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 20 | 21 | #: audiofield/admin.py:37 22 | #, python-format 23 | msgid "Successfully deleted %d audio files." 24 | msgstr "Eliminado correctamente %d archivos de audio." 25 | 26 | #: audiofield/fields.py:87 27 | msgid "not allowed filetype!" 28 | msgstr "" 29 | 30 | #: audiofield/fields.py:94 31 | msgid "" 32 | "not allowed : file format conversion is not allowed for same audio type " 33 | "(except Wav)" 34 | msgstr "" 35 | 36 | #: audiofield/models.py:35 37 | #, fuzzy 38 | #| msgid "Audio Name" 39 | msgid "audio name" 40 | msgstr "Nombre de audio" 41 | 42 | #: audiofield/models.py:36 43 | #, fuzzy 44 | #| msgid "Audio file label" 45 | msgid "audio file label" 46 | msgstr "Etiqueta del audio" 47 | 48 | #: audiofield/models.py:39 audiofield/models.py:50 49 | #, fuzzy 50 | #| msgid "Audio file" 51 | msgid "audio file" 52 | msgstr "Archivo de audio" 53 | 54 | #: audiofield/models.py:40 55 | msgid "user" 56 | msgstr "" 57 | 58 | #: audiofield/models.py:41 59 | #, fuzzy 60 | #| msgid "Select User" 61 | msgid "select user" 62 | msgstr "Seleccione Usuario" 63 | 64 | #: audiofield/models.py:47 65 | #, fuzzy 66 | #| msgid "Audio files" 67 | msgid "can see Audio Files" 68 | msgstr "Los archivos de audio" 69 | 70 | #: audiofield/models.py:51 71 | #, fuzzy 72 | #| msgid "Audio files" 73 | msgid "audio files" 74 | msgstr "Los archivos de audio" 75 | 76 | #: audiofield/models.py:69 77 | #, fuzzy 78 | #| msgid "Audio file player" 79 | msgid "audio file player" 80 | msgstr "Reproductor de archivos de audio" 81 | 82 | #: audiofield/widgets.py:24 audiofield/widgets.py:30 83 | msgid "Keep original" 84 | msgstr "Conservar original" 85 | 86 | #: audiofield/widgets.py:25 87 | msgid "Mono" 88 | msgstr "Mono" 89 | 90 | #: audiofield/widgets.py:26 91 | msgid "Stereo" 92 | msgstr "Estéreo" 93 | 94 | #: audiofield/widgets.py:31 95 | msgid "8000 Hz" 96 | msgstr "8000 Hz" 97 | 98 | #: audiofield/widgets.py:32 99 | msgid "16000 Hz" 100 | msgstr "16.000 Hz" 101 | 102 | #: audiofield/widgets.py:33 103 | msgid "22050 Hz" 104 | msgstr "22050 Hz" 105 | 106 | #: audiofield/widgets.py:34 107 | msgid "44100 Hz" 108 | msgstr "44100 Hz" 109 | 110 | #: audiofield/widgets.py:35 111 | msgid "48000 Hz" 112 | msgstr "48000 Hz" 113 | 114 | #: audiofield/widgets.py:39 115 | msgid "Keep original audio file" 116 | msgstr "Mantener el archivo de audio original" 117 | 118 | #: audiofield/widgets.py:40 119 | msgid "Convert to MP3" 120 | msgstr "Convertir a MP3" 121 | 122 | #: audiofield/widgets.py:41 123 | msgid "Convert to WAV" 124 | msgstr "Convertir a WAV" 125 | 126 | #: audiofield/widgets.py:42 127 | msgid "Convert to OGG" 128 | msgstr "Convertir a OGG" 129 | 130 | #: audiofield/widgets.py:79 131 | msgid "Allowed format - mp3 wav and ogg" 132 | msgstr "Formato permite - mp3 wav y ogg" 133 | 134 | #: audiofield/widgets.py:83 audiofield/widgets.py:141 135 | msgid "Currently:" 136 | msgstr "En la actualidad:" 137 | 138 | #: audiofield/widgets.py:85 audiofield/widgets.py:143 139 | msgid "Change:" 140 | msgstr "Cambio:" 141 | 142 | #: audiofield/widgets.py:87 143 | msgid "Upload:" 144 | msgstr "Subir:" 145 | 146 | #: audiofield/widgets.py:89 147 | #, fuzzy 148 | #| msgid "Convert To:" 149 | msgid "Convert to:" 150 | msgstr "Convertir a:" 151 | 152 | #: audiofield/widgets.py:90 153 | msgid "Channel:" 154 | msgstr "Canal:" 155 | 156 | #: audiofield/widgets.py:91 157 | msgid "Frequency:" 158 | msgstr "Frecuencia:" 159 | 160 | #: audiofield/widgets.py:95 161 | msgid "Delete:" 162 | msgstr "Eliminar:" 163 | 164 | #: audiofield/widgets.py:133 165 | msgid "Allowed format - mp3, wav and ogg" 166 | msgstr "Formato permite - mp3, wav y ogg" 167 | 168 | #~ msgid "English" 169 | #~ msgstr "Inglés" 170 | 171 | #~ msgid "Spanish" 172 | #~ msgstr "Español" 173 | 174 | #~ msgid "Portuguese" 175 | #~ msgstr "Portugués" 176 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/basic.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | SoundManager 2 Demo: Play MP3 links on a page, "page as playlist" style 6 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 68 | 69 | 70 | 79 | 80 | 81 | 82 | 83 |
84 | 85 |
86 | 87 |
88 | 89 | 97 | 98 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/source/includes/introduction.txt: -------------------------------------------------------------------------------- 1 | :Version: |version| 2 | :Release: |release| 3 | :Date: |today| 4 | :Keywords: django, python, audiofield, audio, wav, mp3, sox 5 | 6 | -- 7 | 8 | .. _django-audiofield-synopsis: 9 | 10 | Django-audiofield is an application written in Python, using the ``Django`` Framework. 11 | 12 | The license is MIT. 13 | 14 | 15 | 16 | .. _overview: 17 | 18 | Overview 19 | ======== 20 | 21 | Django-audiofield is a Django application which allows audio file upload and conversion to mp3, wav and ogg format. 22 | It also makes it easy to play the audio files into your django application, for this we integrated a HTML5 and Flash audio player 'SoundManager2' 23 | 24 | The goal of this project is to quickly manage audio files into your django project and make it easy for admins and users to listen to them. 25 | 26 | 27 | .. image:: ./_static/django-admin-audiofield.png 28 | :width: 792 29 | 30 | .. image:: ./_static/django-admin-audiofield-upload.png 31 | :width: 792 32 | 33 | More information about Soundmanager2 : http://www.schillmania.com/projects/soundmanager2/ 34 | 35 | 36 | .. _usage: 37 | 38 | Usage 39 | ===== 40 | 41 | 42 | Add the following lines in your models.py file:: 43 | 44 | from django.conf import settings 45 | from audiofield.fields import AudioField 46 | import os.path 47 | 48 | # Add the audio field to your model 49 | audio_file = AudioField(upload_to='your/upload/dir', blank=True, 50 | ext_whitelist=(".mp3", ".wav", ".ogg"), 51 | help_text=("Allowed type - .mp3, .wav, .ogg")) 52 | 53 | # Add this method to your model 54 | def audio_file_player(self): 55 | """audio player tag for admin""" 56 | if self.audio_file: 57 | file_url = settings.MEDIA_URL + str(self.audio_file) 58 | player_string = '' % (file_url) 59 | return player_string 60 | audio_file_player.allow_tags = True 61 | audio_file_player.short_description = _('Audio file player') 62 | 63 | 64 | Add the following lines in your admin.py:: 65 | 66 | from your_app.models import your_model_name 67 | 68 | # add 'audio_file_player' tag to your admin view 69 | list_display = (..., 'audio_file_player', ...) 70 | actions = ['custom_delete_selected'] 71 | 72 | def custom_delete_selected(self, request, queryset): 73 | #custom delete code 74 | n = queryset.count() 75 | for i in queryset: 76 | if i.audio_file: 77 | if os.path.exists(i.audio_file.path): 78 | os.remove(i.audio_file.path) 79 | i.delete() 80 | self.message_user(request, _("Successfully deleted %d audio files.") % n) 81 | custom_delete_selected.short_description = "Delete selected items" 82 | 83 | def get_actions(self, request): 84 | actions = super(AudioFileAdmin, self).get_actions(request) 85 | del actions['delete_selected'] 86 | return actions 87 | 88 | 89 | If you are not using the installation script, please copy following template file to your template directory:: 90 | 91 | cp audiofield/templates/common_audiofield.html /path/to/your/templates/directory/ 92 | 93 | 94 | Add the following in your template files (like admin/change_form.html, admin/change_list.html, etc... in which you are using audio field type):: 95 | 96 | {% block extrahead %} 97 | {{ block.super }} 98 | {% include "common_audiofield.html" %} 99 | {% endblock %} 100 | 101 | 102 | Then perform following commands to create the table and collect the static files:: 103 | 104 | ./manage.py syncdb 105 | 106 | and then:: 107 | 108 | ./manage.py collectstatic 109 | 110 | 111 | Create audiofield.log file:: 112 | 113 | touch /var/log/audio-field.log 114 | 115 | 116 | 117 | .. _documentation: 118 | 119 | Documentation 120 | ============= 121 | 122 | Extensive documentation is available on 'Read the Docs': 123 | http://django-audiofield.readthedocs.org 124 | 125 | 126 | .. _contributing: 127 | 128 | Contributing 129 | ============ 130 | 131 | If you've found a bug, implemented a feature or customized the template and 132 | think it is useful then please consider contributing. Patches, pull requests or 133 | just suggestions are welcome! 134 | 135 | Source code: http://github.com/Star2Billing/django-audiofield 136 | 137 | 138 | If you don’t like Github and Git you’re welcome to send regular patches. 139 | 140 | Bug tracker: https://github.com/Star2Billing/django-audiofield/issues 141 | 142 | .. _license: 143 | 144 | License 145 | ======= 146 | 147 | Copyright (c) 2011-2014 Star2Billing S.L. 148 | 149 | django-audiofield is licensed under MIT, see `MIT-LICENSE.txt`. 150 | 151 | 152 | .. _credit: 153 | 154 | Credit 155 | ====== 156 | 157 | Django-audiofield is a Star2Billing-Sponsored Community Project, for more information visit 158 | http://www.star2billing.com or email us at info@star2billing.com 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | 15 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " singlehtml to make a single large HTML file" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " devhelp to make HTML files and a Devhelp project" 27 | @echo " epub to make an epub" 28 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 29 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 30 | @echo " text to make text files" 31 | @echo " man to make manual pages" 32 | @echo " changes to make an overview of all changed/added/deprecated items" 33 | @echo " linkcheck to check all external links for integrity" 34 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 35 | 36 | clean: 37 | -rm -rf $(BUILDDIR)/* 38 | 39 | html: 40 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 43 | 44 | dirhtml: 45 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 48 | 49 | singlehtml: 50 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 51 | @echo 52 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 53 | 54 | pickle: 55 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 56 | @echo 57 | @echo "Build finished; now you can process the pickle files." 58 | 59 | json: 60 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 61 | @echo 62 | @echo "Build finished; now you can process the JSON files." 63 | 64 | htmlhelp: 65 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 66 | @echo 67 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 68 | ".hhp project file in $(BUILDDIR)/htmlhelp." 69 | 70 | qthelp: 71 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 72 | @echo 73 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 74 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 75 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-audiofield.qhcp" 76 | @echo "To view the help file:" 77 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-audiofield.qhc" 78 | 79 | devhelp: 80 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 81 | @echo 82 | @echo "Build finished." 83 | @echo "To view the help file:" 84 | @echo "# mkdir -p $$HOME/.local/share/devhelp/django-audiofield" 85 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-audiofield" 86 | @echo "# devhelp" 87 | 88 | epub: 89 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 90 | @echo 91 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 92 | 93 | latex: 94 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 95 | @echo 96 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 97 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 98 | "(use \`make latexpdf' here to do that automatically)." 99 | 100 | latexpdf: 101 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 102 | @echo "Running LaTeX files through pdflatex..." 103 | make -C $(BUILDDIR)/latex all-pdf 104 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 105 | 106 | text: 107 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 108 | @echo 109 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 110 | 111 | man: 112 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 113 | @echo 114 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 115 | 116 | changes: 117 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 118 | @echo 119 | @echo "The overview file is in $(BUILDDIR)/changes." 120 | 121 | linkcheck: 122 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 123 | @echo 124 | @echo "Link check complete; look for any errors in the above output " \ 125 | "or in $(BUILDDIR)/linkcheck/output.txt." 126 | 127 | doctest: 128 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 129 | @echo "Testing of doctests in the sources finished, look at the " \ 130 | "results in $(BUILDDIR)/doctest/output.txt." 131 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/flashblock/method1/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | SoundManager 2: Flash blocker handling examples 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 45 | 46 | 47 | 48 |
49 | 50 |

SoundManager 2: Flashblock / "click to flash" handling demos

51 | 52 |

Show SWF inline, wait indefinitely for load

53 | 54 |

You can run this demo with Flash 8 (default), Flash 9 (normal mode) or Flash 9 + highPerformance mode (higher JS callback frequency).

55 | 56 |

Typically SM2 appends a DIV and hides the SWF off-screen. To handle potential flash block cases, a flash container DIV with an ID of "sm2-container" is placed in the HTML. SM2 will find and append the flash movie to this element. In this case, the SWF can be targeted with CSS and is not positioned off-screen as it normally would be.

57 |

SM2 will start its init process, and will fire onready(), onload() and onerror() handlers accordingly. Keep in mind that while onerror() may fire at first, it may be preceded by a successful onload() if the user first loads the page and then later unblocks the flash movie.

58 |

Note that flash blockers may not run when viewing offline (via file://) content, so try viewing this demo online. For FlashBlock (under Firefox), you can also adjust flashblock.blockLocal under about:config in the address bar to test while offline.

59 | 60 |

CSS applied to #sm2-container, depending on state:

61 |
#sm2-container.movieContainer {/* Initial state: position:absolute/off-screen, or inline/relative */}
62 | #sm2-container.swf_timedout {/* Didn't load before time-out, show to user: On-screen, red border, etc..? */}
63 | #sm2-container.swf_unblocked {/* Applied if a timeout followed by an unblock (flash started.) Move off-screen. */}
64 | #sm2-container.high_performance {/* Additional modifier for "high performance" mode, should apply position:fixed and left/bottom 0 to stay on-screen at all times (better flash performance) */}
65 | #sm2-container.flash_debug {/* Additional modifier for flash debug output mode, should use width/height 100% so you can read debug messages */}
66 | #sm2-container.swf_error {/* Additional modifier, "something really broke" (fatal: security, missing SWF etc.) */}
67 | 68 |

SoundManager 2 load status: Loading...

69 | 70 |

Take a look at flashblock.css for implementation details.

71 | 72 |
73 | 74 |
75 | 76 |
77 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | if NOT "%PAPER%" == "" ( 11 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 12 | ) 13 | 14 | if "%1" == "" goto help 15 | 16 | if "%1" == "help" ( 17 | :help 18 | echo.Please use `make ^` where ^ is one of 19 | echo. html to make standalone HTML files 20 | echo. dirhtml to make HTML files named index.html in directories 21 | echo. singlehtml to make a single large HTML file 22 | echo. pickle to make pickle files 23 | echo. json to make JSON files 24 | echo. htmlhelp to make HTML files and a HTML help project 25 | echo. qthelp to make HTML files and a qthelp project 26 | echo. devhelp to make HTML files and a Devhelp project 27 | echo. epub to make an epub 28 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 29 | echo. text to make text files 30 | echo. man to make manual pages 31 | echo. changes to make an overview over all changed/added/deprecated items 32 | echo. linkcheck to check all external links for integrity 33 | echo. doctest to run all doctests embedded in the documentation if enabled 34 | goto end 35 | ) 36 | 37 | if "%1" == "clean" ( 38 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 39 | del /q /s %BUILDDIR%\* 40 | goto end 41 | ) 42 | 43 | if "%1" == "html" ( 44 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 45 | if errorlevel 1 exit /b 1 46 | echo. 47 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 48 | goto end 49 | ) 50 | 51 | if "%1" == "dirhtml" ( 52 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 53 | if errorlevel 1 exit /b 1 54 | echo. 55 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 56 | goto end 57 | ) 58 | 59 | if "%1" == "singlehtml" ( 60 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 61 | if errorlevel 1 exit /b 1 62 | echo. 63 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 64 | goto end 65 | ) 66 | 67 | if "%1" == "pickle" ( 68 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 69 | if errorlevel 1 exit /b 1 70 | echo. 71 | echo.Build finished; now you can process the pickle files. 72 | goto end 73 | ) 74 | 75 | if "%1" == "json" ( 76 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished; now you can process the JSON files. 80 | goto end 81 | ) 82 | 83 | if "%1" == "htmlhelp" ( 84 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished; now you can run HTML Help Workshop with the ^ 88 | .hhp project file in %BUILDDIR%/htmlhelp. 89 | goto end 90 | ) 91 | 92 | if "%1" == "qthelp" ( 93 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 94 | if errorlevel 1 exit /b 1 95 | echo. 96 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 97 | .qhcp project file in %BUILDDIR%/qthelp, like this: 98 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-audiofield.qhcp 99 | echo.To view the help file: 100 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-audiofield.ghc 101 | goto end 102 | ) 103 | 104 | if "%1" == "devhelp" ( 105 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 106 | if errorlevel 1 exit /b 1 107 | echo. 108 | echo.Build finished. 109 | goto end 110 | ) 111 | 112 | if "%1" == "epub" ( 113 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 117 | goto end 118 | ) 119 | 120 | if "%1" == "latex" ( 121 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 122 | if errorlevel 1 exit /b 1 123 | echo. 124 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 125 | goto end 126 | ) 127 | 128 | if "%1" == "text" ( 129 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 130 | if errorlevel 1 exit /b 1 131 | echo. 132 | echo.Build finished. The text files are in %BUILDDIR%/text. 133 | goto end 134 | ) 135 | 136 | if "%1" == "man" ( 137 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 141 | goto end 142 | ) 143 | 144 | if "%1" == "changes" ( 145 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.The overview file is in %BUILDDIR%/changes. 149 | goto end 150 | ) 151 | 152 | if "%1" == "linkcheck" ( 153 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Link check complete; look for any errors in the above output ^ 157 | or in %BUILDDIR%/linkcheck/output.txt. 158 | goto end 159 | ) 160 | 161 | if "%1" == "doctest" ( 162 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 163 | if errorlevel 1 exit /b 1 164 | echo. 165 | echo.Testing of doctests in the sources finished, look at the ^ 166 | results in %BUILDDIR%/doctest/output.txt. 167 | goto end 168 | ) 169 | 170 | :end 171 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/css/optional-themes.css: -------------------------------------------------------------------------------- 1 | /* 2 | --------------------------------- 3 | -- alternate (optional) themes -- 4 | --------------------------------- 5 | */ 6 | 7 | ul.playlist.dark li.sm2_playing a { 8 | color:#fff; 9 | } 10 | 11 | ul.playlist.dark li.sm2_playing .timing, 12 | ul.playlist.use-peak.dark li.sm2_playing .peak { 13 | color:#999; 14 | } 15 | 16 | ul.playlist.use-spectrum.dark li.sm2_playing .spectrum-container { 17 | background-color:#222; 18 | border-color:#444; 19 | } 20 | 21 | ul.playlist.use-spectrum.dark li.sm2_playing .spectrum-container .spectrum { 22 | background-color:#999; 23 | } 24 | 25 | ul.playlist.dark li.sm2_paused { 26 | background-color:#333; 27 | } 28 | 29 | ul.playlist.dark li.sm2_paused a { 30 | color:#999; 31 | } 32 | 33 | ul.playlist.dark li.sm2_playing, 34 | ul.playlist.dark li.sm2_playing:hover { 35 | background-color:#333; 36 | } 37 | 38 | ul.playlist.dark li:hover .controls .statusbar { 39 | background-color:#666; 40 | } 41 | 42 | ul.playlist.dark li .controls { 43 | background-color:#333; 44 | } 45 | 46 | ul.playlist.dark li .controls .statusbar { 47 | background-color:#666; 48 | border-color:#444; 49 | } 50 | 51 | ul.playlist.dark li .controls .statusbar .position { 52 | background-color:#111; 53 | border-right:3px solid #111; 54 | border-radius:3px; 55 | -moz-border-radius:3px; 56 | -webkit-border-radius:3px; 57 | } 58 | 59 | ul.playlist.dark li .controls .statusbar .loading { 60 | background-color:#444; 61 | } 62 | 63 | ul.playlist.dark li .timing, 64 | ul.playlist.use-peak.dark li .peak { 65 | background-color:#222; 66 | border-color:#444; 67 | } 68 | 69 | ul.playlist.dark.use-peak li .peak .l, 70 | ul.playlist.dark.use-peak li .peak .r { 71 | border-color:#444; 72 | background-color:#999; 73 | } 74 | 75 | 76 | /* gold theme */ 77 | 78 | ul.playlist.gold li.sm2_paused { 79 | background-color:#996600; 80 | } 81 | 82 | ul.playlist.gold li.sm2_playing, 83 | ul.playlist.gold li.sm2_playing:hover { 84 | background-color:#cc9900; 85 | } 86 | 87 | ul.playlist.gold li .controls { 88 | background-color:transparent; 89 | } 90 | 91 | ul.playlist.gold li .controls .statusbar { 92 | background-color:#fff; 93 | border-color:#fff; 94 | } 95 | 96 | ul.playlist.gold li .controls .statusbar .position { 97 | background-color:#996600; 98 | border-right:3px solid #996600; 99 | border-radius:3px; 100 | -moz-border-radius:3px; 101 | -webkit-border-radius:3px; 102 | } 103 | 104 | ul.playlist.gold li .controls .statusbar .loading { 105 | background-color:#ffeedd; 106 | } 107 | 108 | ul.playlist.gold li .timing, 109 | ul.playlist.use-peak.gold li .peak { 110 | background-color:#CC9900; 111 | border-color:#ffcc33; 112 | } 113 | 114 | ul.playlist.use-spectrum.gold li.sm2_playing .spectrum-container { 115 | background-color:#cc9900; 116 | border-color:#ffcc33; 117 | } 118 | 119 | ul.playlist.use-spectrum.gold li.sm2_playing .spectrum-container .spectrum { 120 | background-color:#fff; 121 | } 122 | 123 | ul.playlist.gold.use-peak li .peak .l, 124 | ul.playlist.gold.use-peak li .peak .r { 125 | border-color:#fff; 126 | background-color:#fff; 127 | } 128 | 129 | 130 | /* ZOMG PONIES!!!ONEONEONE */ 131 | 132 | ul.playlist.bubblegum li a { 133 | font-family:"comic sans ms",verdana,arial,tahoma,"sans serif"; /* heh */ 134 | } 135 | 136 | ul.playlist.bubblegum li.sm2_paused, 137 | ul.playlist.bubblegum li.sm2_paused:hover { 138 | background-color:#ffccee; 139 | } 140 | 141 | ul.playlist.bubblegum li.sm2_paused a, 142 | ul.playlist.bubblegum li.sm2_paused:hover a, 143 | ul.playlist.bubblegum li.sm2_paused .timing, 144 | ul.playlist.use-peak.bubblegum li.sm2_paused .peak { 145 | color:#ff6699; 146 | } 147 | 148 | ul.playlist.bubblegum li:hover { 149 | background-color:#ffddee; 150 | } 151 | 152 | ul.playlist.bubblegum li.sm2_playing, 153 | ul.playlist.bubblegum li.sm2_playing:hover { 154 | background-color:#ff7799; 155 | } 156 | 157 | ul.playlist.bubblegum li .controls { 158 | background-color:transparent; 159 | } 160 | 161 | ul.playlist.bubblegum li .controls .statusbar { 162 | background-color:#fff; 163 | border-color:#fff; 164 | } 165 | 166 | ul.playlist.bubblegum li .controls .statusbar .position { 167 | background-color:#ffaacc; 168 | border-right:3px solid #ffaacc; 169 | border-radius:3px; 170 | -moz-border-radius:3px; 171 | -webkit-border-radius:3px; 172 | } 173 | 174 | ul.playlist.bubblegum li .controls .statusbar .loading { 175 | background-color:#ffeedd; 176 | } 177 | 178 | ul.playlist.bubblegum li .timing, 179 | ul.playlist.use-peak.bubblegum li .peak { 180 | background-color:#ffaacc; 181 | border-color:#ffccee; 182 | } 183 | 184 | ul.playlist.use-spectrum.bubblegum li.sm2_playing .spectrum-container { 185 | background-color:#ffaacc; 186 | border-color:#ffccee; 187 | } 188 | 189 | ul.playlist.use-spectrum.bubblegum li.sm2_playing .spectrum-container .spectrum { 190 | background-color:#fff; 191 | } 192 | 193 | ul.playlist.bubblegum.use-peak li .peak .l, 194 | ul.playlist.bubblegum.use-peak li .peak .r { 195 | border-color:#fff; 196 | background-color:#fff; 197 | } 198 | 199 | 200 | ul.playlist.shiny li.sm2_paused, 201 | ul.playlist.shiny li.sm2_playing { 202 | background-image:url(../image/top-highlight.png); 203 | background-repeat:repeat-x; 204 | background-position:0px -1px; 205 | _background-image:none; /* can't be bothered with IE 6. */ 206 | } -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/script/optional-page-player-metadata.js: -------------------------------------------------------------------------------- 1 | // SoundManager 2: Page Player demo, MetaData UI prototype 2 | 3 | /*jslint white: false, onevar: true, undef: true, nomen: false, eqeqeq: true, plusplus: false, bitwise: true, newcap: true, immed: true */ 4 | /*global pagePlayer, document, window */ 5 | 6 | var Metadata = function(oSound) { 7 | 8 | var self = this, 9 | pl = pagePlayer, 10 | oLI = oSound._data.oLI, 11 | o = oLI.getElementsByTagName('ul')[0], 12 | oItems = o.getElementsByTagName('li'), 13 | oTemplate = document.createElement('div'), 14 | oTemplate2 = document.createElement('div'), 15 | oTemplate3 = document.createElement('div'), 16 | oDuration, i; 17 | 18 | oTemplate.innerHTML = ' '; 19 | oTemplate.className = 'annotation'; 20 | oTemplate2.innerHTML = ' '; 21 | oTemplate2.className = 'annotation alt'; 22 | oTemplate3.className = 'note'; 23 | 24 | this.totalTime = 0; 25 | this.data = []; 26 | this.data.givenDuration = null; 27 | this.data.currentItem = null; 28 | this.data.mainTitle = oSound._data.oLink.innerHTML; 29 | 30 | this.strToTime = function(sTime) { 31 | var segments = sTime.split(':'), 32 | seconds = 0, i; 33 | for (i=segments.length; i--;) { 34 | seconds += parseInt(segments[i],10)*Math.pow(60,segments.length-1-i); // hours, minutes 35 | } 36 | return seconds; 37 | }; 38 | 39 | // make stuff 40 | this.createElements = function() { 41 | var oFrag = document.createDocumentFragment(), 42 | oNode = null, 43 | oNodeSpan = null, 44 | oNode2 = null, i; 45 | for (i=0; i= metadata[i].startTimeMS && now <= metadata[i].endTimeMS) { 73 | index = i; 74 | break; 75 | } 76 | } 77 | if (index !== metadata.currentItem) { 78 | // update 79 | oSound._data.oLink.innerHTML = metadata.mainTitle+' '; 80 | pl.setPageTitle(metadata[index].title+' | '+metadata.mainTitle); 81 | metadata.currentItem = index; 82 | } 83 | }; 84 | 85 | this.refresh = function() { 86 | var offset = 0, 87 | relWidth = null, 88 | duration = (self.data.givenDuration?self.data.givenDuration:oSound.durationEstimate), i; 89 | for (i=0; i`_ 7 | 8 | .. _Areski: https://github.com/areski/ 9 | 10 | .. image:: https://img.shields.io/pypi/v/django-audiofield.svg 11 | :target: https://pypi.python.org/pypi/django-audiofield/ 12 | :alt: Latest Version 13 | 14 | .. image:: https://img.shields.io/pypi/dm/django-audiofield.svg 15 | :target: https://pypi.python.org/pypi/django-audiofield/ 16 | :alt: Downloads 17 | 18 | .. image:: https://img.shields.io/pypi/pyversions/django-audiofield.svg 19 | :target: https://pypi.python.org/pypi/django-audiofield/ 20 | :alt: Supported Python versions 21 | 22 | .. image:: https://img.shields.io/pypi/l/django-audiofield.svg 23 | :target: https://pypi.python.org/pypi/django-audiofield/ 24 | :alt: License 25 | 26 | 27 | Django-Audiofield is a simple app that allows Audio files upload, management and conversion to different audio format (mp3, wav & ogg), which also makes it easy to play audio files into your Django application. 28 | 29 | We are using the HTML5 and Flash audio player SoundManager2_ 30 | 31 | .. _SoundManager2: http://www.schillmania.com/projects/soundmanager2/ 32 | 33 | .. image:: https://github.com/Star2Billing/django-audiofield/raw/master/docs/source/_static/django-admin-audiofield.png 34 | 35 | .. image:: https://github.com/Star2Billing/django-audiofield/raw/master/docs/source/_static/django-admin-audiofield-upload.png 36 | 37 | 38 | Installation 39 | ============ 40 | 41 | Install Django-Audiofield:: 42 | 43 | python setup.py install 44 | 45 | 46 | Dependencies 47 | ------------ 48 | 49 | Install dependencies on Debian:: 50 | 51 | apt-get -y install libsox-fmt-mp3 libsox-fmt-all mpg321 dir2ogg ffmpeg 52 | 53 | Note: For Debian version 7 (Wheezy) and older, replace `ffmpeg` with `libav-tools` 54 | 55 | 56 | Install dependencies on Redhat/CentOS:: 57 | 58 | yum -y install python-setuptools libsox-fmt-mp3 libsox-fmt-all mpg321 dir2ogg 59 | 60 | 61 | Install avconv on Redhat/CentOS:: 62 | 63 | git clone git://git.libav.org/libav.git 64 | cd libav 65 | sudo ./configure --disable-yasm 66 | sudo make 67 | sudo make install 68 | 69 | 70 | Settings 71 | ======== 72 | 73 | in your settings.py file:: 74 | 75 | # Set Following variable 76 | MEDIA_ROOT = '' 77 | MEDIA_URL = '' 78 | 79 | In MIDDLEWARE_CLASSES add 'audiofield.middleware.threadlocals.ThreadLocals' 80 | 81 | In INSTALLED_APPS add 'audiofield' 82 | 83 | # Frontend widget values 84 | # 0-Keep original, 1-Mono, 2-Stereo 85 | CHANNEL_TYPE_VALUE = 0 86 | 87 | # 0-Keep original, 8000-8000Hz, 16000-16000Hz, 22050-22050Hz, 88 | # 44100-44100Hz, 48000-48000Hz, 96000-96000Hz 89 | FREQ_TYPE_VALUE = 8000 90 | 91 | # 0-Keep original, 1-Convert to MP3, 2-Convert to WAV, 3-Convert to OGG 92 | CONVERT_TYPE_VALUE = 0 93 | 94 | 95 | Usage 96 | ===== 97 | 98 | Add the following lines in your models.py file:: 99 | 100 | from django.conf import settings 101 | from audiofield.fields import AudioField 102 | import os.path 103 | 104 | # Add the audio field to your model 105 | audio_file = AudioField(upload_to='your/upload/dir', blank=True, 106 | ext_whitelist=(".mp3", ".wav", ".ogg"), 107 | help_text=("Allowed type - .mp3, .wav, .ogg")) 108 | 109 | # Add this method to your model 110 | def audio_file_player(self): 111 | """audio player tag for admin""" 112 | if self.audio_file: 113 | file_url = settings.MEDIA_URL + str(self.audio_file) 114 | player_string = '' % (file_url) 115 | return player_string 116 | 117 | audio_file_player.allow_tags = True 118 | audio_file_player.short_description = ('Audio file player') 119 | 120 | 121 | Add the following lines in your admin.py:: 122 | 123 | from your_app.models import your_model_name 124 | 125 | # add 'audio_file_player' tag to your admin view 126 | list_display = (..., 'audio_file_player', ...) 127 | actions = ['custom_delete_selected'] 128 | 129 | def custom_delete_selected(self, request, queryset): 130 | #custom delete code 131 | n = queryset.count() 132 | for i in queryset: 133 | if i.audio_file: 134 | if os.path.exists(i.audio_file.path): 135 | os.remove(i.audio_file.path) 136 | i.delete() 137 | self.message_user(request, ("Successfully deleted %d audio files.") % n) 138 | custom_delete_selected.short_description = "Delete selected items" 139 | 140 | def get_actions(self, request): 141 | actions = super(AudioFileAdmin, self).get_actions(request) 142 | del actions['delete_selected'] 143 | return actions 144 | 145 | 146 | Then perform following commands to create the table and collect the static files:: 147 | 148 | ./manage.py syncdb 149 | ./manage.py collectstatic 150 | 151 | 152 | Create audiofield.log file:: 153 | 154 | touch /var/log/audio-field.log 155 | 156 | 157 | Contributing 158 | ============ 159 | 160 | If you've found a bug, implemented a feature or customized the template and 161 | think it is useful then please consider contributing. Patches, pull requests or 162 | just suggestions are welcome! 163 | 164 | Source code: http://github.com/Star2Billing/django-audiofield 165 | 166 | Bug tracker: https://github.com/Star2Billing/django-audiofield/issues 167 | 168 | 169 | Documentation 170 | ============= 171 | 172 | Documentation is available on 'Read the Docs': 173 | http://django-audiofield.readthedocs.org 174 | 175 | 176 | Credit 177 | ====== 178 | 179 | Django-audiofield is a Star2Billing-Sponsored Community Project, for more information visit http://www.star2billing.com or email us at info@star2billing.com 180 | 181 | 182 | License 183 | ======= 184 | 185 | Django-Audiofield is licensed under MIT, see `MIT-LICENSE.txt`. 186 | 187 | 188 | TODO 189 | ==== 190 | 191 | - Use pydub (http://pydub.com) to lift the audio conversion away from django-audiofield 192 | 193 | - integrate with django-storage (http://django-storages.readthedocs.org/) 194 | 195 | - support more formats 196 | -------------------------------------------------------------------------------- /audiofield/widgets.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | from __future__ import unicode_literals 14 | 15 | from django.contrib.admin.widgets import AdminFileWidget 16 | from django import forms 17 | from django.utils.translation import gettext_lazy as _ 18 | from django.utils.safestring import mark_safe 19 | from django.conf import settings 20 | import os.path 21 | 22 | 23 | CHANNEL_TYPE = ( 24 | ('0', _('Keep original')), 25 | ('1', _('Mono')), 26 | ('2', _('Stereo')), 27 | ) 28 | 29 | FREQ_TYPE = ( 30 | ('0', _('Keep original')), 31 | ('8000', _('8000 Hz')), 32 | ('16000', _('16000 Hz')), 33 | ('22050', _('22050 Hz')), 34 | ('44100', _('44100 Hz')), 35 | ('48000', _('48000 Hz')), 36 | ) 37 | 38 | CONVERT_TYPE = ( 39 | ('0', _('Keep original audio file')), 40 | ('1', _('Convert to MP3')), 41 | ('2', _('Convert to WAV')), 42 | ('3', _('Convert to OGG')), 43 | ) 44 | 45 | 46 | def add_select_box(select_name, select_value): 47 | ''' 48 | function to create Html select option 49 | ''' 50 | select_box = '' 54 | return select_box 55 | 56 | 57 | class AdminAudioFileWidget(AdminFileWidget): 58 | ''' 59 | A AdminFileWidget that shows 60 | - audio player to play uploaded file 61 | - file browser 62 | - audio type conversion 63 | - If conversion is mp3 to wav, you can add channel type & frequency 64 | - a delete checkbox 65 | ''' 66 | input_type = 'file' 67 | 68 | def render(self, name, value, attrs=None, renderer=None): 69 | input = super(forms.widgets.FileInput, self).render(name, value, attrs) 70 | 71 | file_select_box = add_select_box('convert_type', CONVERT_TYPE) 72 | channel_select_box = add_select_box('channel_type', CHANNEL_TYPE) 73 | freq_select_box = add_select_box('freq_type', FREQ_TYPE) 74 | 75 | file_url = '' 76 | item = '%s%s' 77 | output = [] 78 | output.append('') 79 | help_text = _('Allowed format - mp3 wav and ogg') 80 | if value and type(value).__name__ != 'str': 81 | file_url = settings.MEDIA_URL + str(value) 82 | output.append(item % ( 83 | _('Currently:'), 84 | '' % (file_url))) 85 | output.append(item % (_('Change:'), input + '
%s' % help_text)) 86 | else: 87 | output.append(item % (_('Upload:'), input + '
%s' % help_text)) 88 | 89 | output.append(item % (_('Convert to:'), file_select_box)) 90 | output.append(item % (_('Channel:'), channel_select_box)) 91 | output.append(item % (_('Frequency:'), freq_select_box)) 92 | 93 | if value: 94 | # split colon to force "Delete" that is already translated 95 | output.append(item % (_('Delete:'), '' % name)) 96 | output.append('
') 97 | 98 | return mark_safe(''.join(output)) 99 | 100 | def value_from_datadict(self, data, files, name): 101 | if not data.get('%s_delete' % name): 102 | return super(AdminAudioFileWidget, self).value_from_datadict(data, files, name) 103 | else: 104 | return '__deleted__' 105 | 106 | 107 | class CustomerAudioFileWidget(AdminFileWidget): 108 | ''' 109 | A CustomerAudioFileWidget that shows 110 | - audio player to play uploaded file 111 | - file browser 112 | - hidden variables which are set in settings.py 113 | - audio type conversion 114 | - If conversion is mp3 to wav, you can add channel type & frequency 115 | ''' 116 | input_type = 'file' 117 | 118 | def render(self, name, value, attrs=None, renderer=None): 119 | input = super(forms.widgets.FileInput, self).render(name, value, attrs) 120 | 121 | file_url = '' 122 | 123 | file_select_box = '' % settings.CONVERT_TYPE_VALUE 124 | channel_select_box = '' % settings.CHANNEL_TYPE_VALUE 125 | freq_select_box = '' % settings.FREQ_TYPE_VALUE 126 | 127 | output = [] 128 | 129 | label_style = 'float:left;line-height:18px;padding-top:6px;text-align:right;' 130 | input_div_style = 'width:300px;margin-left:70px;' 131 | 132 | item = '
%s
%s
' 133 | help_text = '%s' % _('Allowed format - mp3, wav and ogg') 134 | 135 | form_var = 0 136 | if value and type(value).__name__ != 'str': 137 | dst_fullpath = os.path.join(settings.MEDIA_ROOT, str(value)) 138 | if os.path.isfile(dst_fullpath): 139 | file_url = settings.MEDIA_URL + str(value) 140 | output.append(item % ( 141 | _('Currently:'), 142 | '' % (file_url))) 143 | output.append(item % (_('Change:'), input + help_text)) 144 | form_var = 1 # no error 145 | else: 146 | form_var = 0 # form error 147 | 148 | # default 149 | if form_var == 0: 150 | input_div_style = 'width:300px;' 151 | item = '
%s
%s
' 152 | output.append(item % ('', input + help_text)) 153 | 154 | output.append(item % (file_select_box, '')) 155 | output.append(item % (channel_select_box, '')) 156 | output.append(item % (freq_select_box, '')) 157 | 158 | return mark_safe(''.join(output)) 159 | 160 | def value_from_datadict(self, data, files, name): 161 | if not data.get('%s_delete' % name): 162 | return super(CustomerAudioFileWidget, self).value_from_datadict(data, files, name) 163 | else: 164 | return '__deleted__' 165 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/flashblock/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | SoundManager 2: Flash Block handling examples 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
54 | 55 |

SoundManager 2: Flashblock / "click to flash" handling demos

56 | 57 |

Show SWF inline, wait indefinitely for load (click-to-run or whitelist)

58 | 59 |

You can run this demo with Flash 8 (default), Flash 9 (normal mode) or Flash 9 + highPerformance mode (higher JS callback frequency).

60 | 61 |

Where (and when) to show the SWF

62 | 63 |

To handle potential flash block cases, put <div id="sm2-container"></div> in your markup where you'd like the SWF to appear in those cases. If not specified, SM2 will create and append the #sm2-container node to the document when it starts.

64 | 65 |

When soundManager.useFlashBlock is true, SM2 will not apply styles (eg. style.position.left) directly to the flash; rather, it will assign CSS classes and you can handle it as you choose. Take a look at the related CSS file you will also need if you turn this feature on.

66 | 67 |

Handling failed start-up cases

68 | 69 |

In the blocked/failed start-up case, #sm2-container will have a class name of swf_timedout applied to it.

70 | 71 |

SM2 will start its init process, and will fire onready(), onload() and onerror() handlers accordingly. Keep in mind that while onerror() may fire at first, it may be preceded by a successful onload() if the user first loads the page and then later unblocks the flash movie.

72 | 73 |

Note that flash blockers may not run when viewing offline (via file://) content, so try viewing this demo online. For FlashBlock (under Firefox), you can also go to about:config using your address bar and change the value of flashblock.blockLocal to test while offline.

74 | 75 |

Flash Block Example

76 | 77 |

Here, Flash is appended by SM2 to the #sm2-container DIV and after a failed start attempt (if you have a blocker active), will have a swf_timedout class appended.

78 | 79 |

The SWF uses position:absolute and negative left/top values so as not to affect the normal page layout, but shifts to left:auto;top:auto (effectively left/top:0) in the blocked case, and becomes visible to the user. On a successful unblock, the movie goes back to left/top:-9999em and is hidden from view.

80 | 81 |

SoundManager 2 load status: Loading...

82 | 83 | 84 | 85 |
86 | 87 |
88 | 89 |

Flash Block-related CSS

90 | 91 |

When soundManager.useFlashBlock is enabled, CSS is applied to #sm2-container depending on the progress of SM2's start-up.

92 |

This page + demos use the rules below, fully-defined and commented in flashblock.css. Use it as a base for your own SM2 + flash block implementations.

93 | 94 |
#sm2-container {
 95 |  /* Initial state: position:absolute/off-screen, or left/top:0 */
 96 | }
 97 | #sm2-container.swf_timedout {
 98 |   /* Didn't load before time-out, show to user.
 99 |   Maybe highlight on-screen, red border, etc..? */
100 | }
101 | #sm2-container.swf_unblocked {
102 |   /* Applied if movie loads successfully after
103 |   an unblock (flash started, so move off-screen etc.) */
104 | }
105 | #sm2-container.swf_loaded {
106 |   /* Applied if movie loads, regardless of whether
107 |   it was initially blocked */
108 | }
109 | #sm2-container.swf_error {
110 |   /* "Fatal" error case: SWF loaded,
111 |   but SM2 was unable to start for some reason.
112 |   (Flash security or other error case.) */
113 | }
114 | #sm2-container.high_performance {
115 |   /* Additional modifier for "high performance" mode
116 |   should apply position:fixed and left/bottom 0 to stay on-screen
117 |   at all times (better flash performance) */
118 | }
119 | #sm2-container.flash_debug {
120 |   /* Additional modifier for flash debug output mode
121 |   should use width/height 100% so you can read debug messages */
122 | }
123 | 124 |

Basic Demo

125 | 126 |

For a more minimal example, see the basic flashblock demo.

127 | 128 |
129 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/page-player/css/page-player.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SoundManager 2: "page as playlist" example 4 | ------------------------------------------ 5 | http://schillmania.com/projects/soundmanager2/ 6 | 7 | */ 8 | 9 | .spectrum-container { 10 | display:none; 11 | } 12 | 13 | ul.use-spectrum li.sm2_playing .spectrum-container { 14 | position:absolute; 15 | left:0px; 16 | top:0px; 17 | margin-left:-266px; 18 | margin-top:-1px; 19 | display:block; 20 | background-color:#5588bb; 21 | border:1px solid #99ccff; 22 | -moz-border-radius:4px; 23 | -webkit-border-radius:4px; 24 | border-radius:4px; 25 | } 26 | 27 | ul.use-spectrum .spectrum-box { 28 | position:relative; 29 | width:255px; 30 | font-size:1em; 31 | padding:2px 0px; 32 | height:1.2em; 33 | overflow:hidden; 34 | } 35 | 36 | ul.use-spectrum .spectrum-box .spectrum { 37 | position:absolute; 38 | left:0px; 39 | top:-2px; 40 | margin-top:20px; 41 | display:block; 42 | font-size:1px; 43 | width:1px; 44 | height:1px; /* set to 50px for a thick line, 1px for a thin line, etc. */ 45 | overflow:hidden; 46 | background-color:#fff; 47 | } 48 | 49 | ul.playlist { 50 | list-style-type:none; 51 | margin:0px; 52 | padding:0px; 53 | 54 | } 55 | 56 | ul.playlist li { 57 | /* assume all items will be sounds rather than wait for onload etc. in this example.. may differ for your uses. */ 58 | position:relative; 59 | display:block; 60 | width:auto; 61 | font-size:2em; 62 | color:#666; 63 | padding:0.25em 0.5em 0.25em 0.5em; 64 | border:none; 65 | letter-spacing:-1px; /* ZOMG WEB X.0. ;) */ 66 | background-color:#f9f9f9; 67 | -webkit-transition-property: hover; 68 | -webkit-transition: background-color 0.15s ease-in-out; 69 | -moz-transition: background-color 0.15s linear 0s; /* firefox 4 */ 70 | -o-transition-property: background-color; /* opera 10.5 */ 71 | -o-transition-duration: 0.15s; 72 | 73 | } 74 | 75 | ul.playlist li a { 76 | display:block; 77 | text-decoration:none; 78 | font-weight:normal; 79 | color:#000; 80 | font-size:120%; 81 | outline:none; 82 | position:relative; 83 | z-index:2; 84 | } 85 | 86 | ul.playlist li.sm2_playing, 87 | ul.playlist li.sm2_paused, 88 | ul.playlist li.sm2_playing a { 89 | color:#fff; 90 | border-radius:3px; 91 | -webkit-border-radius:3px; 92 | -moz-border-radius:3px; 93 | } 94 | 95 | ul.playlist li:hover { 96 | background-color:#eee; 97 | } 98 | 99 | ul.playlist li:hover a { 100 | color:#333; 101 | } 102 | 103 | ul.playlist li.sm2_playing, 104 | ul.playlist li.sm2_playing:hover { 105 | background-color:#6699cc; 106 | } 107 | 108 | ul.playlist li.sm2_paused { 109 | background-color:#999; 110 | } 111 | 112 | ul.playlist li.sm2_playing:hover a, 113 | ul.playlist li.sm2_paused a { 114 | color:#fff; 115 | } 116 | 117 | ul.playlist li .controls { 118 | display:none; 119 | } 120 | 121 | ul.playlist li .peak, 122 | ul.playlist.use-peak li .peak { 123 | display:none; 124 | position:absolute; 125 | top:0.55em; 126 | right:0.5em; 127 | } 128 | 129 | ul.playlist li.sm2_playing .controls, 130 | ul.playlist li.sm2_paused .controls { 131 | position:relative; 132 | display:block; 133 | } 134 | 135 | ul.playlist.use-peak li.sm2_playing .peak, 136 | ul.playlist.use-peak li.sm2_paused .peak { 137 | display:inline; 138 | display:inline-block; 139 | } 140 | 141 | ul.playlist.use-peak li .peak { 142 | display:none; /* IE 7 */ 143 | } 144 | 145 | ul.playlist li.sm2_paused .controls { 146 | background-color:#666; 147 | } 148 | 149 | ul.playlist li:hover .controls .statusbar { 150 | position:relative; 151 | cursor:ew-resize; 152 | cursor:-moz-grab; 153 | cursor:grab; 154 | } 155 | 156 | ul.playlist li.sm2_paused .controls .statusbar { 157 | background-color:#ccc; 158 | } 159 | 160 | ul.playlist li .controls { 161 | position:relative; 162 | margin-top:0.25em; 163 | margin-bottom:0.25em; 164 | background-color:#99ccff; 165 | } 166 | 167 | ul.playlist li .controls .statusbar { 168 | position:relative; 169 | height:0.5em; 170 | background-color:#ccddff; 171 | border:2px solid #fff; 172 | border-radius:2px; 173 | -moz-border-radius:2px; 174 | -webkit-border-radius:2px; 175 | overflow:hidden; 176 | cursor:-moz-grab; 177 | cursor:grab; 178 | } 179 | 180 | ul.playlist li .controls.dragging .statusbar { 181 | cursor:-moz-grabbing; 182 | cursor:grabbing; 183 | } 184 | 185 | ul.playlist li .controls .statusbar .position, 186 | ul.playlist li .controls .statusbar .loading, 187 | ul.playlist li .controls .statusbar .annotation { 188 | position:absolute; 189 | left:0px; 190 | top:0px; 191 | height:0.5em; 192 | } 193 | 194 | ul.playlist li .controls .statusbar .position { 195 | background-color:#336699; 196 | border-right:3px solid #336699; 197 | border-radius:3px; 198 | -moz-border-radius:3px; 199 | -webkit-border-radius:3px; 200 | } 201 | 202 | ul.playlist li.sm2_paused .controls .statusbar .position { 203 | background-color:#666; 204 | border-color:#666; 205 | } 206 | 207 | ul.playlist li .controls .statusbar .loading { 208 | background-color:#eee; 209 | } 210 | 211 | ul.playlist li .controls .statusbar .position, 212 | ul.playlist li .controls .statusbar .loading { 213 | width:0px; 214 | } 215 | 216 | ul.playlist li.sm2_playing a.sm2_link, 217 | ul.playlist li.sm2_paused a.sm2_link { 218 | margin-right:4.5em; /* room for timing stuff */ 219 | } 220 | 221 | ul.playlist li .timing { 222 | position:absolute; 223 | display:none; 224 | text-align:right; 225 | right:1em; 226 | top:1em; 227 | width:auto; 228 | height:1em; 229 | padding:3px 5px; 230 | background-color:#5588bb; 231 | border:1px solid #99ccff; 232 | -moz-border-radius:4px; 233 | -khtml-border-radius:4px; 234 | border-radius:4px; 235 | letter-spacing:0px; 236 | font:44% monaco,"VT-100","lucida console",courier,system; 237 | line-height:1em; 238 | vertical-align:middle; 239 | } 240 | 241 | ul.playlist.use-peak li .timing { 242 | right:4.25em; 243 | } 244 | 245 | ul.playlist li:hover .timing { 246 | z-index:2; 247 | } 248 | 249 | ul.playlist li .timing div.sm2_timing { 250 | margin:0px; 251 | padding:0px; 252 | margin-top:-1em; 253 | } 254 | 255 | ul.playlist li.sm2_playing .timing, 256 | ul.playlist li.sm2_paused .timing { 257 | display:block; 258 | } 259 | 260 | ul.playlist li.sm2_paused .timing .sm2_position { 261 | text-decoration:blink; /* hee hee. first actual appropriate use? :D */ 262 | } 263 | 264 | ul.playlist li.sm2_paused .timing, 265 | ul.playlist.use-peak li.sm2_paused .peak { 266 | background-color:#888; 267 | border-color:#ccc; 268 | } 269 | 270 | /* peak data */ 271 | 272 | /* ul.playlist ... */ 273 | 274 | ul.playlist.use-peak li .peak { 275 | display:none; 276 | zoom:1; 277 | border:1px solid #99ccff; 278 | padding:2px; 279 | height:0.55em; 280 | -moz-border-radius:4px; 281 | -khtml-border-radius:4px; 282 | border-radius:4px; 283 | background-color:#5588bb; 284 | width:0.8em; 285 | height:0.55em; 286 | margin-top:-3px; 287 | } 288 | 289 | ul.playlist.use-peak li .peak-box { 290 | position:relative; 291 | width:100%; 292 | height:0.55em; 293 | overflow:hidden; 294 | } 295 | 296 | ul.playlist li .peak .l, 297 | ul.playlist li .peak .r { 298 | position:absolute; 299 | left:0px; 300 | top:0px; 301 | width:7px; 302 | height:50px; 303 | background:#fff; 304 | border:1px solid #fff; 305 | -moz-border-radius:1px; 306 | -khtml-border-radius:1px; 307 | margin-top:1em; 308 | } 309 | 310 | ul.playlist li .peak .l { 311 | margin-right:1px; 312 | } 313 | 314 | ul.playlist li .peak .r { 315 | left:10px; 316 | } 317 | 318 | #control-template { 319 | display:none; 320 | } -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # django-audiofield documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Dec 8 12:55:34 2011. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys 15 | import os 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | #sys.path.insert(0, os.path.abspath('.')) 21 | sys.path.insert(0, os.path.abspath('../../')) 22 | 23 | 24 | import audiofield 25 | # -- General configuration ----------------------------------------------------- 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | #needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be extensions 31 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 32 | extensions = [] 33 | 34 | # Add any paths that contain templates here, relative to this directory. 35 | templates_path = ['_templates'] 36 | 37 | # The suffix of source filenames. 38 | source_suffix = '.rst' 39 | 40 | # The encoding of source files. 41 | #source_encoding = 'utf-8-sig' 42 | 43 | # The master toctree document. 44 | master_doc = 'index' 45 | 46 | # General information about the project. 47 | project = u'django-audiofield' 48 | copyright = u'2011-2014, Arezqui Belaid (Star2Billing)' 49 | 50 | # The version info for the project you're documenting, acts as replacement for 51 | # |version| and |release|, also used in various other places throughout the 52 | # built documents. 53 | # 54 | # The short X.Y version. 55 | version = audiofield.__version__ 56 | # The full version, including alpha/beta/rc tags. 57 | release = audiofield.__version__ 58 | 59 | # The language for content autogenerated by Sphinx. Refer to documentation 60 | # for a list of supported languages. 61 | #language = None 62 | 63 | # There are two options for replacing |today|: either, you set today to some 64 | # non-false value, then it is used: 65 | #today = '' 66 | # Else, today_fmt is used as the format for a strftime call. 67 | #today_fmt = '%B %d, %Y' 68 | 69 | # List of patterns, relative to source directory, that match files and 70 | # directories to ignore when looking for source files. 71 | exclude_patterns = [] 72 | 73 | # The reST default role (used for this markup: `text`) to use for all documents. 74 | #default_role = None 75 | 76 | # If true, '()' will be appended to :func: etc. cross-reference text. 77 | #add_function_parentheses = True 78 | 79 | # If true, the current module name will be prepended to all description 80 | # unit titles (such as .. function::). 81 | #add_module_names = True 82 | 83 | # If true, sectionauthor and moduleauthor directives will be shown in the 84 | # output. They are ignored by default. 85 | #show_authors = False 86 | 87 | # The name of the Pygments (syntax highlighting) style to use. 88 | pygments_style = 'sphinx' 89 | 90 | # A list of ignored prefixes for module index sorting. 91 | #modindex_common_prefix = [] 92 | 93 | 94 | # -- Options for HTML output --------------------------------------------------- 95 | 96 | # The theme to use for HTML and HTML Help pages. See the documentation for 97 | # a list of builtin themes. 98 | html_theme = 'default' 99 | 100 | # Theme options are theme-specific and customize the look and feel of a theme 101 | # further. For a list of options available for each theme, see the 102 | # documentation. 103 | #html_theme_options = {} 104 | 105 | # Add any paths that contain custom themes here, relative to this directory. 106 | #html_theme_path = [] 107 | 108 | # The name for this set of Sphinx documents. If None, it defaults to 109 | # " v documentation". 110 | #html_title = None 111 | 112 | # A shorter title for the navigation bar. Default is the same as html_title. 113 | #html_short_title = None 114 | 115 | # The name of an image file (relative to this directory) to place at the top 116 | # of the sidebar. 117 | #html_logo = None 118 | 119 | # The name of an image file (within the static path) to use as favicon of the 120 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 121 | # pixels large. 122 | #html_favicon = None 123 | 124 | # Add any paths that contain custom static files (such as style sheets) here, 125 | # relative to this directory. They are copied after the builtin static files, 126 | # so a file named "default.css" will overwrite the builtin "default.css". 127 | html_static_path = ['_static'] 128 | 129 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 130 | # using the given strftime format. 131 | #html_last_updated_fmt = '%b %d, %Y' 132 | 133 | # If true, SmartyPants will be used to convert quotes and dashes to 134 | # typographically correct entities. 135 | #html_use_smartypants = True 136 | 137 | # Custom sidebar templates, maps document names to template names. 138 | #html_sidebars = {} 139 | 140 | # Additional templates that should be rendered to pages, maps page names to 141 | # template names. 142 | #html_additional_pages = {} 143 | 144 | # If false, no module index is generated. 145 | #html_domain_indices = True 146 | 147 | # If false, no index is generated. 148 | #html_use_index = True 149 | 150 | # If true, the index is split into individual pages for each letter. 151 | #html_split_index = False 152 | 153 | # If true, links to the reST sources are added to the pages. 154 | #html_show_sourcelink = True 155 | 156 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 157 | #html_show_sphinx = True 158 | 159 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 160 | #html_show_copyright = True 161 | 162 | # If true, an OpenSearch description file will be output, and all pages will 163 | # contain a tag referring to it. The value of this option must be the 164 | # base URL from which the finished HTML is served. 165 | #html_use_opensearch = '' 166 | 167 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 168 | #html_file_suffix = None 169 | 170 | # Output file base name for HTML help builder. 171 | htmlhelp_basename = 'django-audiofielddoc' 172 | 173 | 174 | # -- Options for LaTeX output -------------------------------------------------- 175 | 176 | # The paper size ('letter' or 'a4'). 177 | #latex_paper_size = 'letter' 178 | 179 | # The font size ('10pt', '11pt' or '12pt'). 180 | #latex_font_size = '10pt' 181 | 182 | # Grouping the document tree into LaTeX files. List of tuples 183 | # (source start file, target name, title, author, documentclass [howto/manual]). 184 | latex_documents = [ 185 | ('index', 'django-audiofield.tex', u'django-audiofield Documentation', 186 | u'Arezqui Belaid', 'manual'), 187 | ] 188 | 189 | # The name of an image file (relative to this directory) to place at the top of 190 | # the title page. 191 | #latex_logo = None 192 | 193 | # For "manual" documents, if this is true, then toplevel headings are parts, 194 | # not chapters. 195 | #latex_use_parts = False 196 | 197 | # If true, show page references after internal links. 198 | #latex_show_pagerefs = False 199 | 200 | # If true, show URL addresses after external links. 201 | #latex_show_urls = False 202 | 203 | # Additional stuff for the LaTeX preamble. 204 | #latex_preamble = '' 205 | 206 | # Documents to append as an appendix to all manuals. 207 | #latex_appendices = [] 208 | 209 | # If false, no module index is generated. 210 | #latex_domain_indices = True 211 | 212 | 213 | # -- Options for manual page output -------------------------------------------- 214 | 215 | # One entry per manual page. List of tuples 216 | # (source start file, name, description, authors, manual section). 217 | man_pages = [ 218 | ('index', 'django-audiofield', u'django-audiofield Documentation', 219 | [u'Arezqui Belaid'], 1) 220 | ] 221 | -------------------------------------------------------------------------------- /audiofield/fields.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-audiofield License 3 | # 4 | # This Source Code Form is subject to the terms of the Mozilla Public 5 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 6 | # You can obtain one at http://mozilla.org/MPL/2.0/. 7 | # 8 | # Copyright (C) 2011-2014 Star2Billing S.L. 9 | # 10 | # The Initial Developer of the Original Code is 11 | # Arezqui Belaid 12 | # 13 | 14 | from django.db.models.fields.files import FileField 15 | from django.db.models import signals 16 | from django.conf import settings 17 | from django.core.files.storage import FileSystemStorage 18 | from django.utils.translation import gettext_lazy as _ 19 | from django import forms 20 | from celery.utils.log import get_task_logger 21 | from audiofield.middleware import threadlocals 22 | from audiofield.tasks import audio_convert_task 23 | import os 24 | import subprocess 25 | import shutil 26 | from random import choice, seed 27 | 28 | seed() 29 | logger = get_task_logger(__name__) 30 | CONVERT_TYPE_CHK = {0: 'org', 1: 'mp3', 2: 'wav', 3: 'ogg'} 31 | 32 | 33 | def random_string(char_length=5, digit_length=10): 34 | chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 35 | digit = "1234567890" 36 | pass_str_char = ''.join([choice(chars) for i in range(char_length)]) 37 | pass_str_digit = ''.join([choice(digit) for i in range(digit_length)]) 38 | return pass_str_char + '-' + pass_str_digit 39 | 40 | 41 | class StdAudioField: 42 | ''' 43 | Instances of this class will be used to access data of the converted 44 | audio files 45 | ''' 46 | def __init__(self, name): 47 | self.name = name 48 | self.storage = FileSystemStorage() 49 | 50 | def path(self): 51 | return self.storage.path(self.name) 52 | 53 | def url(self): 54 | return self.storage.url(self.name) 55 | 56 | def size(self): 57 | return self.storage.size(self.name) 58 | 59 | 60 | class AudioField(FileField): 61 | ''' 62 | Django field that behaves as FileField, with some extra features like: 63 | - Audio Player 64 | - Delete specific file 65 | - Convert to specific format 66 | ''' 67 | size = None 68 | uuid = None 69 | filename_prefix = 'audio-file-' 70 | 71 | def __init__(self, *args, **kwargs): 72 | """Get allowed file extension type (ex. mp3, wav)""" 73 | ext_whitelist = kwargs.pop("ext_whitelist", tuple()) 74 | self.ext_whitelist = [i.lower() for i in ext_whitelist] 75 | super(AudioField, self).__init__(*args, **kwargs) 76 | 77 | def clean(self, data, initial=None): 78 | """Audio field validation for file extension""" 79 | data = super(AudioField, self).clean(data, initial) 80 | 81 | request = threadlocals.get_current_request() 82 | 83 | filename = data.name 84 | ext = os.path.splitext(filename)[1] 85 | ext = ext.lower() 86 | if ext not in self.ext_whitelist: 87 | error_msg = _("not allowed filetype!") 88 | logger.error(error_msg) 89 | raise forms.ValidationError(error_msg) 90 | 91 | convert_to = request and int(request.POST["convert_type"]) 92 | ext = ext.split('.')[1] 93 | audio_type = CONVERT_TYPE_CHK[convert_to] 94 | error_msg = _("not allowed : file format conversion is not allowed for same audio type (except Wav)") 95 | if convert_to: 96 | if ext == audio_type and ext != 'wav': 97 | error_msg += ' %s format !!' % ext 98 | logger.error(error_msg) 99 | raise forms.ValidationError(error_msg) 100 | else: 101 | pass 102 | 103 | return data 104 | 105 | def _get_converted_filename(self, filename): 106 | # Not used 107 | '''Returns the audio converted name associated to the standard audio filename 108 | * Example: /var/www/myproject/media/audio/picture_1.wav 109 | will return /var/www/myproject/media/audio/picture_1.converted.wav 110 | ''' 111 | splitted_filename = list(os.path.splitext(filename)) 112 | splitted_filename.insert(1, '.converted') 113 | logger.debug('converted file name') 114 | return ''.join(splitted_filename) 115 | 116 | def _convert_audio(self, filename, instance=None, ext=None): 117 | '''Convert uploaded audio file to selected format''' 118 | request = threadlocals.get_current_request() 119 | 120 | convert_type = 0 121 | channel_no = 0 122 | freq_value = 0 123 | nbchannels = 1 124 | remix = '' 125 | 126 | if 'convert_type' in request.POST: 127 | convert_type = int(request.POST["convert_type"]) 128 | if 'channel_type' in request.POST: 129 | channel_no = int(request.POST["channel_type"]) 130 | if 'freq_type' in request.POST: 131 | freq_value = int(request.POST["freq_type"]) 132 | 133 | logger.info("convert audio : %s->%s" % (str(ext), CONVERT_TYPE_CHK[convert_type])) 134 | splitted_filename = list(os.path.splitext(filename))[0] # converted filename without ext 135 | filename_temp = filename[:-4] + '_temp' 136 | 137 | # Find the number of channels 138 | if os.path.isfile(filename): 139 | command = "soxi -c %s" % filename 140 | response = subprocess.Popen(command.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 141 | (output, error) = response.communicate() 142 | nbchannels = (int(output)) 143 | 144 | # prepare Sox parameters for Channels convertion 145 | conv_channel = "-e signed-integer -c %s" % str(channel_no) if channel_no > 0 else '' 146 | # prepare Sox parameters for Frequency convertion 147 | conv_freq = "-r %s" % str(freq_value) if freq_value > 0 else '' 148 | 149 | if nbchannels == 2: 150 | # sox input.wav output.wav `remix -` performs a mix-down of all input channels to mono. 151 | remix = 'remix -' 152 | 153 | # 1) MP3 TO WAV 154 | if ext == 'mp3' and CONVERT_TYPE_CHK[convert_type] == 'wav': 155 | logger.debug("convert MP3 to WAV - channel %s freq: %s" % (str(channel_no), str(freq_value))) 156 | conv = "sox %s %s %s %s.wav %s" % (filename, conv_freq, conv_channel, splitted_filename, remix) 157 | conv = conv.replace(' ', ' ') 158 | result = audio_convert_task.delay(conv) 159 | logger.debug("Sox command :> %s" % conv) 160 | 161 | # 2) MP3 TO OGG 162 | if ext == 'mp3' and CONVERT_TYPE_CHK[convert_type] == 'ogg': 163 | logger.debug('MP3 to OGG') 164 | conv = "dir2ogg -q 4 %s" % (filename) 165 | result = audio_convert_task.delay(conv) 166 | 167 | # 3) WAV TO MP3 168 | if ext == 'wav' and CONVERT_TYPE_CHK[convert_type] == 'mp3': 169 | logger.debug('WAV to MP3') 170 | conv = "sox %s %s.mp3 %s" % (filename, splitted_filename, remix) 171 | result = audio_convert_task.delay(conv) 172 | logger.debug("Sox command :> %s" % conv) 173 | 174 | # 3) WAV TO WAV 175 | if ext == 'wav' and CONVERT_TYPE_CHK[convert_type] == 'wav': 176 | # if nbchannels == 2: 177 | # remix = 'remix 1,2i' 178 | filename_temp = filename_temp + '.wav' 179 | conv = "sox %s %s %s %s.wav %s" % (filename_temp, conv_freq, conv_channel, splitted_filename, remix) 180 | conv = conv.replace(' ', ' ') 181 | # cmd = 'sox /usr/share/newfies/../newfies/usermedia/upload/audiofiles/audio-file-XFPQN-6216731785_temp.wav -r 8000 -e signed-integer -c 1 /usr/share/newfies/../newfies/usermedia/upload/audiofiles/audio-file-XFPQN-6216731785.wav' 182 | # create a temp copy of the file 183 | shutil.copy2(filename, filename_temp) 184 | result = audio_convert_task.delay(conv) 185 | logger.debug("result :> %s" % str(result)) 186 | 187 | # 4) WAV TO OGG 188 | if ext == 'wav' and CONVERT_TYPE_CHK[convert_type] == 'ogg': 189 | logger.debug('WAV to OGG') 190 | conv = "sox %s %s.ogg %s" % (filename, splitted_filename, remix) 191 | result = audio_convert_task.delay(conv) 192 | 193 | # 5) OGG TO MP3 194 | if ext == 'ogg' and CONVERT_TYPE_CHK[convert_type] == 'mp3': 195 | logger.debug('OGG to MP3') 196 | conv = "sox %s %s.mp3%s" % (filename, splitted_filename, remix) 197 | result = audio_convert_task.delay(conv) 198 | 199 | # 6) OGG TO WAV 200 | if ext == 'ogg' and CONVERT_TYPE_CHK[convert_type] == 'wav': 201 | logger.debug('OGG to WAV') 202 | # conv = "sox %s %s.wav" % (filename, splitted_filename) 203 | conv = "avconv -i %s -map_metadata 0:s:0 %s.wav" % (filename, splitted_filename) 204 | result = audio_convert_task.delay(conv) 205 | 206 | def _rename_audio(self, instance=None, **kwargs): 207 | '''Rename uploaded audio file & calls methods to convert audio file format if 208 | convert_to is selected''' 209 | if getattr(instance, self.name): 210 | filename = getattr(instance, self.name).path 211 | 212 | # Get the extension and limit to 3 chars 213 | ext = os.path.splitext(filename)[1].lower()[:4] 214 | # Get new file name and make sure it's unique 215 | dst = self.generate_filename(instance, '%s%s%s' % (self.filename_prefix, self.uuid, ext)) 216 | dst_fullpath = os.path.join(settings.MEDIA_ROOT, dst) 217 | 218 | # Same file should not exits 219 | if not os.path.isfile(dst_fullpath): 220 | 221 | if os.path.abspath(filename) != os.path.abspath(dst_fullpath): 222 | os.rename(filename, dst_fullpath) 223 | self._convert_audio(dst_fullpath, instance, ext[1:4]) 224 | 225 | request = threadlocals.get_current_request() 226 | convert_type = int(request.POST["convert_type"]) 227 | 228 | # 0 => Keep original 229 | if convert_type > 0: 230 | # Delete original audio file 231 | if os.path.exists(dst_fullpath): 232 | # Check for no .. and no * 233 | # DISABLED Delete file 234 | """ 235 | if dst_fullpath.find('../../') == -1 and dst_fullpath.find('*') == -1: 236 | os.remove(dst_fullpath) 237 | """ 238 | ext = '.' + CONVERT_TYPE_CHK[convert_type] 239 | dst = self.generate_filename(instance, '%s%s%s' % 240 | (self.filename_prefix, self.uuid, ext)) 241 | setattr(instance, self.attname, dst) 242 | instance.save() 243 | else: 244 | error_msg = ("file already exists!") 245 | logger.error(error_msg) 246 | 247 | def _set_audio_converted(self, instance=None, **kwargs): 248 | '''Creates a "audio_field" object as attribute of the FileField instance 249 | audio_field attribute will be of the same class of original file, so 250 | "path", "url", "name"... properties can be used''' 251 | if getattr(instance, self.name): 252 | filename = self.generate_filename(instance, os.path.basename(getattr(instance, self.name).path)) 253 | audio_field = StdAudioField(filename) 254 | setattr(getattr(instance, self.name), 'audio_converted', audio_field) 255 | 256 | def formfield(self, **kwargs): 257 | '''Specify form field and widget to be used on the forms''' 258 | from audiofield.widgets import AdminAudioFileWidget 259 | from audiofield.forms import AudioFormField 260 | kwargs['widget'] = AdminAudioFileWidget 261 | kwargs['form_class'] = AudioFormField 262 | 263 | return super(AudioField, self).formfield(**kwargs) 264 | 265 | def save_form_data(self, instance, data): 266 | '''Overwrite save_form_data to delete audio files if "delete" checkbox 267 | is selected''' 268 | if data == '__deleted__': 269 | filename = getattr(instance, self.name).path 270 | if os.path.exists(filename): 271 | # Check for no .. and no * 272 | if filename.find('../../') == -1 and filename.find('*') == -1: 273 | os.remove(filename) 274 | setattr(instance, self.name, None) 275 | else: 276 | self.uuid = random_string(5, 10) 277 | super(AudioField, self).save_form_data(instance, data) 278 | 279 | def contribute_to_class(self, cls, name): 280 | '''Call methods for generating all operations on specified signals''' 281 | super(AudioField, self).contribute_to_class(cls, name) 282 | signals.post_save.connect(self._rename_audio, sender=cls) 283 | signals.post_init.connect(self._set_audio_converted, sender=cls) 284 | 285 | 286 | try: 287 | from south.modelsinspector import add_introspection_rules 288 | add_introspection_rules([( 289 | [AudioField], 290 | [], 291 | { 292 | "ext_whitelist": ["ext_whitelist", {}], 293 | }, 294 | ), 295 | ], ["^audiofield\.fields\.AudioField"]) 296 | except ImportError: 297 | # South is not enabled 298 | pass 299 | -------------------------------------------------------------------------------- /audiofield/static/audiofield/script/soundmanager2-nodebug-jsmin.js: -------------------------------------------------------------------------------- 1 | /** @license 2 | * 3 | * SoundManager 2: JavaScript Sound for the Web 4 | * ---------------------------------------------- 5 | * http://schillmania.com/projects/soundmanager2/ 6 | * 7 | * Copyright (c) 2007, Scott Schiller. All rights reserved. 8 | * Code provided under the BSD License: 9 | * http://schillmania.com/projects/soundmanager2/license.txt 10 | * 11 | * V2.97a.20110918 12 | */ 13 | (function(Z){function M(M,Y){function j(c){return function(a){return!this._t||!this._t._a?null:c.call(this,a)}}this.flashVersion=8;this.debugFlash=this.debugMode=!1;this.useConsole=!0;this.waitForWindowLoad=this.consoleOnly=!1;this.bgColor="#ffffff";this.useHighPerformance=!1;this.flashPollingInterval=null;this.flashLoadTimeout=1E3;this.wmode=null;this.allowScriptAccess="always";this.useFlashBlock=!1;this.useHTML5Audio=!0;this.html5Test=/^(probably|maybe)$/i;this.preferFlash=!0;this.audioFormats= 14 | {mp3:{type:['audio/mpeg; codecs="mp3"',"audio/mpeg","audio/mp3","audio/MPA","audio/mpa-robust"],required:!0},mp4:{related:["aac","m4a"],type:['audio/mp4; codecs="mp4a.40.2"',"audio/aac","audio/x-m4a","audio/MP4A-LATM","audio/mpeg4-generic"],required:!1},ogg:{type:["audio/ogg; codecs=vorbis"],required:!1},wav:{type:['audio/wav; codecs="1"',"audio/wav","audio/wave","audio/x-wav"],required:!1}};this.defaultOptions={autoLoad:!1,stream:!0,autoPlay:!1,loops:1,onid3:null,onload:null,whileloading:null,onplay:null, 15 | onpause:null,onresume:null,whileplaying:null,onstop:null,onfailure:null,onfinish:null,multiShot:!0,multiShotEvents:!1,position:null,pan:0,type:null,usePolicyFile:!1,volume:100};this.flash9Options={isMovieStar:null,usePeakData:!1,useWaveformData:!1,useEQData:!1,onbufferchange:null,ondataerror:null};this.movieStarOptions={bufferTime:3,serverURL:null,onconnect:null,duration:null};this.movieID="sm2-container";this.id=Y||"sm2movie";this.swfCSS={swfBox:"sm2-object-box",swfDefault:"movieContainer",swfError:"swf_error", 16 | swfTimedout:"swf_timedout",swfLoaded:"swf_loaded",swfUnblocked:"swf_unblocked",sm2Debug:"sm2_debug",highPerf:"high_performance",flashDebug:"flash_debug"};this.debugID="soundmanager-debug";this.debugURLParam=/([#?&])debug=1/i;this.versionNumber="V2.97a.20110918";this.movieURL=this.version=null;this.url=M||null;this.altURL=null;this.enabled=this.swfLoaded=!1;this.oMC=this.o=null;this.sounds={};this.soundIDs=[];this.didFlashBlock=this.specialWmodeCase=this.muted=!1;this.filePattern=null;this.filePatterns= 17 | {flash8:/\.mp3(\?.*)?$/i,flash9:/\.mp3(\?.*)?$/i};this.features={buffering:!1,peakData:!1,waveformData:!1,eqData:!1,movieStar:!1};this.sandbox={};this.hasHTML5=typeof Audio!=="undefined"&&typeof(new Audio).canPlayType!=="undefined";this.html5={usingFlash:null};this.flash={};this.ignoreFlash=this.html5Only=!1;var qa,c=this,N,o=navigator.userAgent,i=Z,$=i.location.href.toString(),h=document,aa,O,g,s=[],F=!1,G=!1,m=!1,t=!1,ra=!1,H,n,ba,z,A,P,sa,ca,x,Q,B,da,ea,R,C,ta,fa,ua,S,va,I=null,ga=null,y,ha,D, 18 | T,U,ia,l,V=!1,ja=!1,wa,xa,q=null,ya,W,J,u,ka,la,za,k,Ha=Array.prototype.slice,K=!1,p,X,Aa,r,Ba,ma=o.match(/(ipad|iphone|ipod)/i),Ia=o.match(/(mobile|pre\/|xoom)/i)||ma,v=o.match(/msie/i),Ja=o.match(/webkit/i),L=o.match(/safari/i)&&!o.match(/chrome/i),Ka=o.match(/opera/i),na=!$.match(/usehtml5audio/i)&&!$.match(/sm2\-ignorebadua/i)&&L&&o.match(/OS X 10_6_([3-7])/i),oa=typeof h.hasFocus!=="undefined"?h.hasFocus():null,E=L&&typeof h.hasFocus==="undefined",Ca=!E,Da=/(mp3|mp4|mpa)/i,pa=h.location?h.location.protocol.match(/http/i): 19 | null,Ea=!pa?"http://":"",Fa=/^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4||m4v|m4a|mp4v|3gp|3g2)\s*(?:$|;)/i,Ga=["mpeg4","aac","flv","mov","mp4","m4v","f4v","m4a","mp4v","3gp","3g2"],La=RegExp("\\.("+Ga.join("|")+")(\\?.*)?$","i");this.mimePattern=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.useAltURL=!pa;this._global_a=null;if(Ia&&(c.useHTML5Audio=!0,c.preferFlash=!1,ma))K=c.ignoreFlash=!0;this.supported=this.ok=function(){return q?m&&!t:c.useHTML5Audio&&c.hasHTML5};this.getMovie=function(c){return N(c)|| 20 | h[c]||i[c]};this.createSound=function(b){function a(){e=T(e);c.sounds[d.id]=new qa(d);c.soundIDs.push(d.id);return c.sounds[d.id]}var e=null,f=null,d=null;if(!m||!c.ok())return ia("soundManager.createSound(): "+y(!m?"notReady":"notOK")),!1;arguments.length===2&&(b={id:arguments[0],url:arguments[1]});d=e=n(b);if(l(d.id,!0))return c.sounds[d.id];if(W(d))f=a(),f._setup_html5(d);else{if(g>8){if(d.isMovieStar===null)d.isMovieStar=d.serverURL||(d.type?d.type.match(Fa):!1)||d.url.match(La);if(d.isMovieStar&& 21 | d.usePeakData)d.usePeakData=!1}d=U(d,"soundManager.createSound(): ");f=a();if(g===8)c.o._createSound(d.id,d.loops||1,d.usePolicyFile);else if(c.o._createSound(d.id,d.url,d.usePeakData,d.useWaveformData,d.useEQData,d.isMovieStar,d.isMovieStar?d.bufferTime:!1,d.loops||1,d.serverURL,d.duration||null,d.autoPlay,!0,d.autoLoad,d.usePolicyFile),!d.serverURL)f.connected=!0,d.onconnect&&d.onconnect.apply(f);!d.serverURL&&(d.autoLoad||d.autoPlay)&&f.load(d)}!d.serverURL&&d.autoPlay&&f.play();return f};this.destroySound= 22 | function(b,a){if(!l(b))return!1;var e=c.sounds[b],f;e._iO={};e.stop();e.unload();for(f=0;f8&&b.match(Fa)||b.match(c.mimePattern)):null};this.canPlayURL=function(b){var a;c.hasHTML5&&(a=J({url:b}));return!q||a?a:b?!!b.match(c.filePattern):null};this.canPlayLink=function(b){return typeof b.type!=="undefined"&&b.type&&c.canPlayMIME(b.type)?!0:c.canPlayURL(b.href)};this.getSoundById=function(b){if(!b)throw Error("soundManager.getSoundById(): sID is null/undefined"); 27 | return c.sounds[b]};this.onready=function(c,a){if(c&&c instanceof Function)return a||(a=i),ba("onready",c,a),z(),!0;else throw y("needFunction","onready");};this.ontimeout=function(c,a){if(c&&c instanceof Function)return a||(a=i),ba("ontimeout",c,a),z({type:"ontimeout"}),!0;else throw y("needFunction","ontimeout");};this._wD=this._writeDebug=function(){return!0};this._debug=function(){};this.reboot=function(){var b,a;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].destruct();try{if(v)ga=c.o.innerHTML; 28 | I=c.o.parentNode.removeChild(c.o)}catch(e){}ga=I=q=null;c.enabled=da=m=V=ja=F=G=t=c.swfLoaded=!1;c.soundIDs=c.sounds=[];c.o=null;for(b in s)if(s.hasOwnProperty(b))for(a=s[b].length;a--;)s[b][a].fired=!1;i.setTimeout(c.beginDelayedInit,20)};this.getMoviePercent=function(){return c.o&&typeof c.o.PercentLoaded!=="undefined"?c.o.PercentLoaded():null};this.beginDelayedInit=function(){ra=!0;B();setTimeout(function(){if(ja)return!1;R();Q();return ja=!0},20);P()};this.destruct=function(){c.disable(!0)};qa= 29 | function(b){var a=this,e,f,d;this.sID=b.id;this.url=b.url;this._iO=this.instanceOptions=this.options=n(b);this.pan=this.options.pan;this.volume=this.options.volume;this._lastURL=null;this.isHTML5=!1;this._a=null;this.id3={};this._debug=function(){};this.load=function(b){var d=null;if(typeof b!=="undefined")a._iO=n(b,a.options),a.instanceOptions=a._iO;else if(b=a.options,a._iO=b,a.instanceOptions=a._iO,a._lastURL&&a._lastURL!==a.url)a._iO.url=a.url,a.url=null;if(!a._iO.url)a._iO.url=a.url;if(a._iO.url=== 30 | a.url&&a.readyState!==0&&a.readyState!==2)return a;a._lastURL=a.url;a.loaded=!1;a.readyState=1;a.playState=0;if(W(a._iO)){if(d=a._setup_html5(a._iO),!d._called_load)a._html5_canplay=!1,d.load(),d._called_load=!0,a._iO.autoPlay&&a.play()}else try{a.isHTML5=!1,a._iO=U(T(a._iO)),g===8?c.o._load(a.sID,a._iO.url,a._iO.stream,a._iO.autoPlay,a._iO.whileloading?1:0,a._iO.loops||1,a._iO.usePolicyFile):c.o._load(a.sID,a._iO.url,!!a._iO.stream,!!a._iO.autoPlay,a._iO.loops||1,!!a._iO.autoLoad,a._iO.usePolicyFile)}catch(e){C({type:"SMSOUND_LOAD_JS_EXCEPTION", 31 | fatal:!0})}return a};this.unload=function(){a.readyState!==0&&(a.isHTML5?(f(),a._a&&(a._a.pause(),ka(a._a))):g===8?c.o._unload(a.sID,"about:blank"):c.o._unload(a.sID),e());return a};this.destruct=function(b){if(a.isHTML5){if(f(),a._a)a._a.pause(),ka(a._a),K||a._remove_html5_events(),a._a._t=null,a._a=null}else a._iO.onfailure=null,c.o._destroySound(a.sID);b||c.destroySound(a.sID,!0)};this.start=this.play=function(b,w){var e,w=w===void 0?!0:w;b||(b={});a._iO=n(b,a._iO);a._iO=n(a._iO,a.options);a.instanceOptions= 32 | a._iO;if(a._iO.serverURL&&!a.connected)return a.getAutoPlay()||a.setAutoPlay(!0),a;W(a._iO)&&(a._setup_html5(a._iO),d());if(a.playState===1&&!a.paused&&(e=a._iO.multiShot,!e))return a;if(!a.loaded)if(a.readyState===0){if(!a.isHTML5)a._iO.autoPlay=!0;a.load(a._iO)}else if(a.readyState===2)return a;if(!a.isHTML5&&g===9&&a.position>0&&a.position===a.duration)a._iO.position=0;if(a.paused&&a.position&&a.position>0)a.resume();else{a.playState=1;a.paused=!1;(!a.instanceCount||a._iO.multiShotEvents||!a.isHTML5&& 33 | g>8&&!a.getAutoPlay())&&a.instanceCount++;a.position=typeof a._iO.position!=="undefined"&&!isNaN(a._iO.position)?a._iO.position:0;if(!a.isHTML5)a._iO=U(T(a._iO));if(a._iO.onplay&&w)a._iO.onplay.apply(a),a._onplay_called=!0;a.setVolume(a._iO.volume,!0);a.setPan(a._iO.pan,!0);a.isHTML5?(d(),e=a._setup_html5(),a.setPosition(a._iO.position),e.play()):c.o._start(a.sID,a._iO.loops||1,g===9?a._iO.position:a._iO.position/1E3)}return a};this.stop=function(b){if(a.playState===1){a._onbufferchange(0);a.resetOnPosition(0); 34 | a.paused=!1;if(!a.isHTML5)a.playState=0;a._iO.onstop&&a._iO.onstop.apply(a);if(a.isHTML5){if(a._a)a.setPosition(0),a._a.pause(),a.playState=0,a._onTimer(),f()}else c.o._stop(a.sID,b),a._iO.serverURL&&a.unload();a.instanceCount=0;a._iO={}}return a};this.setAutoPlay=function(b){a._iO.autoPlay=b;a.isHTML5||(c.o._setAutoPlay(a.sID,b),b&&!a.instanceCount&&a.readyState===1&&a.instanceCount++)};this.getAutoPlay=function(){return a._iO.autoPlay};this.setPosition=function(b){b===void 0&&(b=0);var d=a.isHTML5? 35 | Math.max(b,0):Math.min(a.duration||a._iO.duration,Math.max(b,0));a.position=d;b=a.position/1E3;a.resetOnPosition(a.position);a._iO.position=d;if(a.isHTML5){if(a._a&&a._html5_canplay&&a._a.currentTime!==b)try{a._a.currentTime=b,(a.playState===0||a.paused)&&a._a.pause()}catch(e){}}else b=g===9?a.position:b,a.readyState&&a.readyState!==2&&c.o._setPosition(a.sID,b,a.paused||!a.playState);a.isHTML5&&a.paused&&a._onTimer(!0);return a};this.pause=function(b){if(a.paused||a.playState===0&&a.readyState!== 36 | 1)return a;a.paused=!0;a.isHTML5?(a._setup_html5().pause(),f()):(b||b===void 0)&&c.o._pause(a.sID);a._iO.onpause&&a._iO.onpause.apply(a);return a};this.resume=function(){if(!a.paused)return a;a.paused=!1;a.playState=1;a.isHTML5?(a._setup_html5().play(),d()):(a._iO.isMovieStar&&a.setPosition(a.position),c.o._pause(a.sID));!a._onplay_called&&a._iO.onplay?(a._iO.onplay.apply(a),a._onplay_called=!0):a._iO.onresume&&a._iO.onresume.apply(a);return a};this.togglePause=function(){if(a.playState===0)return a.play({position:g=== 37 | 9&&!a.isHTML5?a.position:a.position/1E3}),a;a.paused?a.resume():a.pause();return a};this.setPan=function(b,d){typeof b==="undefined"&&(b=0);typeof d==="undefined"&&(d=!1);a.isHTML5||c.o._setPan(a.sID,b);a._iO.pan=b;if(!d)a.pan=b,a.options.pan=b;return a};this.setVolume=function(b,d){typeof b==="undefined"&&(b=100);typeof d==="undefined"&&(d=!1);if(a.isHTML5){if(a._a)a._a.volume=Math.max(0,Math.min(1,b/100))}else c.o._setVolume(a.sID,c.muted&&!a.muted||a.muted?0:b);a._iO.volume=b;if(!d)a.volume=b, 38 | a.options.volume=b;return a};this.mute=function(){a.muted=!0;if(a.isHTML5){if(a._a)a._a.muted=!0}else c.o._setVolume(a.sID,0);return a};this.unmute=function(){a.muted=!1;var b=typeof a._iO.volume!=="undefined";if(a.isHTML5){if(a._a)a._a.muted=!1}else c.o._setVolume(a.sID,b?a._iO.volume:a.options.volume);return a};this.toggleMute=function(){return a.muted?a.unmute():a.mute()};this.onposition=function(b,c,d){a._onPositionItems.push({position:b,method:c,scope:typeof d!=="undefined"?d:a,fired:!1});return a}; 39 | this.processOnPosition=function(){var b,d;b=a._onPositionItems.length;if(!b||!a.playState||a._onPositionFired>=b)return!1;for(;b--;)if(d=a._onPositionItems[b],!d.fired&&a.position>=d.position)d.fired=!0,c._onPositionFired++,d.method.apply(d.scope,[d.position]);return!0};this.resetOnPosition=function(b){var d,e;d=a._onPositionItems.length;if(!d)return!1;for(;d--;)if(e=a._onPositionItems[d],e.fired&&b<=e.position)e.fired=!1,c._onPositionFired--;return!0};d=function(){a.isHTML5&&wa(a)};f=function(){a.isHTML5&& 40 | xa(a)};e=function(){a._onPositionItems=[];a._onPositionFired=0;a._hasTimer=null;a._onplay_called=!1;a._a=null;a._html5_canplay=!1;a.bytesLoaded=null;a.bytesTotal=null;a.position=null;a.duration=a._iO&&a._iO.duration?a._iO.duration:null;a.durationEstimate=null;a.failures=0;a.loaded=!1;a.playState=0;a.paused=!1;a.readyState=0;a.muted=!1;a.isBuffering=!1;a.instanceOptions={};a.instanceCount=0;a.peakData={left:0,right:0};a.waveformData={left:[],right:[]};a.eqData=[];a.eqData.left=[];a.eqData.right=[]}; 41 | e();this._onTimer=function(b){var c={};if(a._hasTimer||b)return a._a&&(b||(a.playState>0||a.readyState===1)&&!a.paused)?(a.duration=a._get_html5_duration(),a.durationEstimate=a.duration,b=a._a.currentTime?a._a.currentTime*1E3:0,a._whileplaying(b,c,c,c,c),!0):!1};this._get_html5_duration=function(){var b=a._a?a._a.duration*1E3:a._iO?a._iO.duration:void 0;return b&&!isNaN(b)&&b!==Infinity?b:a._iO?a._iO.duration:null};this._setup_html5=function(b){var b=n(a._iO,b),d=K?c._global_a:a._a;decodeURI(b.url); 42 | var f=d&&d._t?d._t.instanceOptions:null;if(d){if(d._t&&f.url===b.url&&(!a._lastURL||a._lastURL===f.url))return d;K&&d._t&&d._t.playState&&b.url!==f.url&&d._t.stop();e();d.src=b.url;a.url=b.url;a._lastURL=b.url;d._called_load=!1}else if(d=new Audio(b.url),d._called_load=!1,K)c._global_a=d;a.isHTML5=!0;a._a=d;d._t=a;a._add_html5_events();d.loop=b.loops>1?"loop":"";b.autoLoad||b.autoPlay?(d.autobuffer="auto",d.preload="auto",a.load(),d._called_load=!0):(d.autobuffer=!1,d.preload="none");d.loop=b.loops> 43 | 1?"loop":"";return d};this._add_html5_events=function(){if(a._a._added_events)return!1;var b;a._a._added_events=!0;for(b in r)r.hasOwnProperty(b)&&a._a&&a._a.addEventListener(b,r[b],!1);return!0};this._remove_html5_events=function(){var b;a._a._added_events=!1;for(b in r)r.hasOwnProperty(b)&&a._a&&a._a.removeEventListener(b,r[b],!1)};this._onload=function(b){b=!!b;a.loaded=b;a.readyState=b?3:2;a._onbufferchange(0);a._iO.onload&&a._iO.onload.apply(a,[b]);return!0};this._onbufferchange=function(b){if(a.playState=== 44 | 0)return!1;if(b&&a.isBuffering||!b&&!a.isBuffering)return!1;a.isBuffering=b===1;a._iO.onbufferchange&&a._iO.onbufferchange.apply(a);return!0};this._onfailure=function(b,c,d){a.failures++;if(a._iO.onfailure&&a.failures===1)a._iO.onfailure(a,b,c,d)};this._onfinish=function(){var b=a._iO.onfinish;a._onbufferchange(0);a.resetOnPosition(0);if(a.instanceCount){a.instanceCount--;if(!a.instanceCount)a.playState=0,a.paused=!1,a.instanceCount=0,a.instanceOptions={},a._iO={},f();(!a.instanceCount||a._iO.multiShotEvents)&& 45 | b&&b.apply(a)}};this._whileloading=function(b,c,d,e){a.bytesLoaded=b;a.bytesTotal=c;a.duration=Math.floor(d);a.bufferLength=e;if(a._iO.isMovieStar)a.durationEstimate=a.duration;else if(a.durationEstimate=a._iO.duration?a.duration>a._iO.duration?a.duration:a._iO.duration:parseInt(a.bytesTotal/a.bytesLoaded*a.duration,10),a.durationEstimate===void 0)a.durationEstimate=a.duration;a.readyState!==3&&a._iO.whileloading&&a._iO.whileloading.apply(a)};this._whileplaying=function(b,c,d,e,f){if(isNaN(b)||b=== 46 | null)return!1;a.position=b;a.processOnPosition();if(!a.isHTML5&&g>8){if(a._iO.usePeakData&&typeof c!=="undefined"&&c)a.peakData={left:c.leftPeak,right:c.rightPeak};if(a._iO.useWaveformData&&typeof d!=="undefined"&&d)a.waveformData={left:d.split(","),right:e.split(",")};if(a._iO.useEQData&&typeof f!=="undefined"&&f&&f.leftEQ&&(b=f.leftEQ.split(","),a.eqData=b,a.eqData.left=b,typeof f.rightEQ!=="undefined"&&f.rightEQ))a.eqData.right=f.rightEQ.split(",")}a.playState===1&&(!a.isHTML5&&g===8&&!a.position&& 47 | a.isBuffering&&a._onbufferchange(0),a._iO.whileplaying&&a._iO.whileplaying.apply(a));return!0};this._onid3=function(b,c){var d=[],e,f;e=0;for(f=b.length;e0&&a._iO.ondataerror&&a._iO.ondataerror.apply(a)}}; 48 | ea=function(){return h.body||h._docElement||h.getElementsByTagName("div")[0]};N=function(b){return h.getElementById(b)};n=function(b,a){var e={},f,d;for(f in b)b.hasOwnProperty(f)&&(e[f]=b[f]);f=typeof a==="undefined"?c.defaultOptions:a;for(d in f)f.hasOwnProperty(d)&&typeof e[d]==="undefined"&&(e[d]=f[d]);return e};k=function(){function b(a){var a=Ha.call(a),b=a.length;c?(a[1]="on"+a[1],b>3&&a.pop()):b===3&&a.push(!1);return a}function a(a,b){var w=a.shift(),h=[f[b]];if(c)w[h](a[0],a[1]);else w[h].apply(w, 49 | a)}var c=i.attachEvent,f={add:c?"attachEvent":"addEventListener",remove:c?"detachEvent":"removeEventListener"};return{add:function(){a(b(arguments),"add")},remove:function(){a(b(arguments),"remove")}}}();r={abort:j(function(){}),canplay:j(function(){if(this._t._html5_canplay)return!0;this._t._html5_canplay=!0;this._t._onbufferchange(0);var b=!isNaN(this._t.position)?this._t.position/1E3:null;if(this._t.position&&this.currentTime!==b)try{this.currentTime=b}catch(a){}}),load:j(function(){this._t.loaded|| 50 | (this._t._onbufferchange(0),this._t._whileloading(this._t.bytesTotal,this._t.bytesTotal,this._t._get_html5_duration()),this._t._onload(!0))}),emptied:j(function(){}),ended:j(function(){this._t._onfinish()}),error:j(function(){this._t._onload(!1)}),loadeddata:j(function(){var b=this._t,a=b.bytesTotal||1;if(!b._loaded&&!L)b.duration=b._get_html5_duration(),b._whileloading(a,a,b._get_html5_duration()),b._onload(!0)}),loadedmetadata:j(function(){}),loadstart:j(function(){this._t._onbufferchange(1)}), 51 | play:j(function(){this._t._onbufferchange(0)}),playing:j(function(){this._t._onbufferchange(0)}),progress:j(function(b){if(this._t.loaded)return!1;var a,c=0,f=b.target.buffered;a=b.loaded||0;var d=b.total||1;if(f&&f.length){for(a=f.length;a--;)c=f.end(a)-f.start(a);a=c/b.target.duration}isNaN(a)||(this._t._onbufferchange(0),this._t._whileloading(a,d,this._t._get_html5_duration()),a&&d&&a===d&&r.load.call(this,b))}),ratechange:j(function(){}),suspend:j(function(b){r.progress.call(this,b)}),stalled:j(function(){}), 52 | timeupdate:j(function(){this._t._onTimer()}),waiting:j(function(){this._t._onbufferchange(1)})};W=function(b){return!b.serverURL&&(b.type?J({type:b.type}):J({url:b.url})||c.html5Only)};ka=function(b){if(b)b.src=o.match(/gecko/i)?"":"about:blank"};J=function(b){function a(a){return c.preferFlash&&p&&!c.ignoreFlash&&typeof c.flash[a]!=="undefined"&&c.flash[a]}if(!c.useHTML5Audio||!c.hasHTML5)return!1;var e=b.url||null,b=b.type||null,f=c.audioFormats,d;if(b&&c.html5[b]!=="undefined")return c.html5[b]&& 53 | !a(b);if(!u){u=[];for(d in f)f.hasOwnProperty(d)&&(u.push(d),f[d].related&&(u=u.concat(f[d].related)));u=RegExp("\\.("+u.join("|")+")(\\?.*)?$","i")}d=e?e.toLowerCase().match(u):null;if(!d||!d.length)if(b)e=b.indexOf(";"),d=(e!==-1?b.substr(0,e):b).substr(6);else return!1;else d=d[1];return d&&typeof c.html5[d]!=="undefined"?c.html5[d]&&!a(d):(b="audio/"+d,e=c.html5.canPlayType({type:b}),(c.html5[d]=e)&&c.html5[b]&&!a(b))};za=function(){function b(b){var d,e,f=!1;if(!a||typeof a.canPlayType!=="function")return!1; 54 | if(b instanceof Array){d=0;for(e=b.length;d1&&b.stream)b.stream=!1;return b};U=function(b){if(b&&!b.usePolicyFile&&(b.onid3||b.usePeakData||b.useWaveformData||b.useEQData))b.usePolicyFile=!0;return b};ia=function(){};aa= 56 | function(){return!1};ua=function(b){for(var a in b)b.hasOwnProperty(a)&&typeof b[a]==="function"&&(b[a]=aa)};S=function(b){typeof b==="undefined"&&(b=!1);(t||b)&&c.disable(b)};va=function(b){var a=null;if(b)if(b.match(/\.swf(\?.*)?$/i)){if(a=b.substr(b.toLowerCase().lastIndexOf(".swf?")+4))return b}else b.lastIndexOf("/")!==b.length-1&&(b+="/");return(b&&b.lastIndexOf("/")!==-1?b.substr(0,b.lastIndexOf("/")+1):"./")+c.movieURL};ca=function(){g=parseInt(c.flashVersion,10);if(g!==8&&g!==9)c.flashVersion= 57 | g=8;var b=c.debugMode||c.debugFlash?"_debug.swf":".swf";if(c.useHTML5Audio&&!c.html5Only&&c.audioFormats.mp4.required&&g<9)c.flashVersion=g=9;c.version=c.versionNumber+(c.html5Only?" (HTML5-only mode)":g===9?" (AS3/Flash 9)":" (AS2/Flash 8)");g>8?(c.defaultOptions=n(c.defaultOptions,c.flash9Options),c.features.buffering=!0,c.defaultOptions=n(c.defaultOptions,c.movieStarOptions),c.filePatterns.flash9=RegExp("\\.(mp3|"+Ga.join("|")+")(\\?.*)?$","i"),c.features.movieStar=!0):c.features.movieStar=!1; 58 | c.filePattern=c.filePatterns[g!==8?"flash9":"flash8"];c.movieURL=(g===8?"soundmanager2.swf":"soundmanager2_flash9.swf").replace(".swf",b);c.features.peakData=c.features.waveformData=c.features.eqData=g>8};ta=function(b,a){if(!c.o)return!1;c.o._setPolling(b,a)};fa=function(){if(c.debugURLParam.test($))c.debugMode=!0};l=this.getSoundById;D=function(){var b=[];c.debugMode&&b.push(c.swfCSS.sm2Debug);c.debugFlash&&b.push(c.swfCSS.flashDebug);c.useHighPerformance&&b.push(c.swfCSS.highPerf);return b.join(" ")}; 59 | ha=function(){y("fbHandler");var b=c.getMoviePercent(),a=c.swfCSS,e={type:"FLASHBLOCK"};if(c.html5Only)return!1;if(c.ok()){if(c.oMC)c.oMC.className=[D(),a.swfDefault,a.swfLoaded+(c.didFlashBlock?" "+a.swfUnblocked:"")].join(" ")}else{if(q)c.oMC.className=D()+" "+a.swfDefault+" "+(b===null?a.swfTimedout:a.swfError);c.didFlashBlock=!0;z({type:"ontimeout",ignoreInit:!0,error:e});C(e)}};ba=function(b,a,c){typeof s[b]==="undefined"&&(s[b]=[]);s[b].push({method:a,scope:c||null,fired:!1})};z=function(b){b|| 60 | (b={type:"onready"});if(!m&&b&&!b.ignoreInit)return!1;if(b.type==="ontimeout"&&c.ok())return!1;var a={success:b&&b.ignoreInit?c.ok():!t},e=b&&b.type?s[b.type]||[]:[],f=[],d,a=[a],h=q&&c.useFlashBlock&&!c.ok();if(b.error)a[0].error=b.error;b=0;for(d=e.length;b'}if(F&&G)return!1;if(c.html5Only)return ca(),c.oMC=N(c.movieID),O(),G=F=!0,!1;var f=a||c.url,d=c.altURL||f,g;g=ea();var i,l,j=D(),k,m=null,m=(m=h.getElementsByTagName("html")[0])&&m.dir&&m.dir.match(/rtl/i),b=typeof b==="undefined"?c.id:b;ca();c.url=va(pa?f:d);a=c.url;c.wmode=!c.wmode&&c.useHighPerformance?"transparent": 65 | c.wmode;if(c.wmode!==null&&(o.match(/msie 8/i)||!v&&!c.useHighPerformance)&&navigator.platform.match(/win32|win64/i))c.specialWmodeCase=!0,c.wmode=null;g={name:b,id:b,src:a,width:"auto",height:"auto",quality:"high",allowScriptAccess:c.allowScriptAccess,bgcolor:c.bgColor,pluginspage:Ea+"www.macromedia.com/go/getflashplayer",title:"JS/Flash audio component (SoundManager 2)",type:"application/x-shockwave-flash",wmode:c.wmode,hasPriority:"true"};if(c.debugFlash)g.FlashVars="debug=1";c.wmode||delete g.wmode; 66 | if(v)f=h.createElement("div"),l=['',e("movie",a),e("AllowScriptAccess",c.allowScriptAccess),e("quality",g.quality),c.wmode?e("wmode",c.wmode):"",e("bgcolor",c.bgColor),e("hasPriority","true"),c.debugFlash?e("FlashVars",g.FlashVars):"",""].join(""); 67 | else for(i in f=h.createElement("embed"),g)g.hasOwnProperty(i)&&f.setAttribute(i,g[i]);fa();j=D();if(g=ea())if(c.oMC=N(c.movieID)||h.createElement("div"),c.oMC.id){k=c.oMC.className;c.oMC.className=(k?k+" ":c.swfCSS.swfDefault)+(j?" "+j:"");c.oMC.appendChild(f);if(v)i=c.oMC.appendChild(h.createElement("div")),i.className=c.swfCSS.swfBox,i.innerHTML=l;G=!0}else{c.oMC.id=c.movieID;c.oMC.className=c.swfCSS.swfDefault+" "+j;i=j=null;if(!c.useFlashBlock)if(c.useHighPerformance)j={position:"fixed",width:"8px", 68 | height:"8px",bottom:"0px",left:"0px",overflow:"hidden"};else if(j={position:"absolute",width:"6px",height:"6px",top:"-9999px",left:"-9999px"},m)j.left=Math.abs(parseInt(j.left,10))+"px";if(Ja)c.oMC.style.zIndex=1E4;if(!c.debugFlash)for(k in j)j.hasOwnProperty(k)&&(c.oMC.style[k]=j[k]);try{v||c.oMC.appendChild(f);g.appendChild(c.oMC);if(v)i=c.oMC.appendChild(h.createElement("div")),i.className=c.swfCSS.swfBox,i.innerHTML=l;G=!0}catch(n){throw Error(y("domError")+" \n"+n.toString());}}return F=!0}; 69 | Q=function(){if(c.html5Only)return R(),!1;if(c.o)return!1;c.o=c.getMovie(c.id);if(!c.o)I?(v?c.oMC.innerHTML=ga:c.oMC.appendChild(I),I=null,F=!0):R(c.id,c.url),c.o=c.getMovie(c.id);c.oninitmovie instanceof Function&&setTimeout(c.oninitmovie,1);return!0};P=function(){setTimeout(sa,1E3)};sa=function(){if(V)return!1;V=!0;k.remove(i,"load",P);if(E&&!oa)return!1;var b;m||(b=c.getMoviePercent());setTimeout(function(){b=c.getMoviePercent();!m&&Ca&&(b===null?c.useFlashBlock||c.flashLoadTimeout===0?c.useFlashBlock&& 70 | ha():S(!0):c.flashLoadTimeout!==0&&S(!0))},c.flashLoadTimeout)};x=function(){function b(){k.remove(i,"focus",x);k.remove(i,"load",x)}if(oa||!E)return b(),!0;oa=Ca=!0;L&&E&&k.remove(i,"mousemove",x);V=!1;b();return!0};Ba=function(){var b,a=[];if(c.useHTML5Audio&&c.hasHTML5)for(b in c.audioFormats)c.audioFormats.hasOwnProperty(b)&&a.push(b+": "+c.html5[b]+(!c.html5[b]&&p&&c.flash[b]?" (using flash)":c.preferFlash&&c.flash[b]&&p?" (preferring flash)":!c.html5[b]?" ("+(c.audioFormats[b].required?"required, ": 71 | "")+"and no flash support)":""))};H=function(b){if(m)return!1;if(c.html5Only)return m=!0,A(),!0;var a;if(!c.useFlashBlock||!c.flashLoadTimeout||c.getMoviePercent())m=!0,t&&(a={type:!p&&q?"NO_FLASH":"INIT_TIMEOUT"});if(t||b){if(c.useFlashBlock&&c.oMC)c.oMC.className=D()+" "+(c.getMoviePercent()===null?c.swfCSS.swfTimedout:c.swfCSS.swfError);z({type:"ontimeout",error:a});C(a);return!1}if(c.waitForWindowLoad&&!ra)return k.add(i,"load",A),!1;else A();return!0};O=function(){if(m)return!1;if(c.html5Only){if(!m)k.remove(i, 72 | "load",c.beginDelayedInit),c.enabled=!0,H();return!0}Q();try{c.o._externalInterfaceTest(!1),ta(!0,c.flashPollingInterval||(c.useHighPerformance?10:50)),c.debugMode||c.o._disableDebug(),c.enabled=!0,c.html5Only||k.add(i,"unload",aa)}catch(b){return C({type:"JS_TO_FLASH_EXCEPTION",fatal:!0}),S(!0),H(),!1}H();k.remove(i,"load",c.beginDelayedInit);return!0};B=function(){if(da)return!1;da=!0;fa();if(!p&&c.hasHTML5)c.useHTML5Audio=!0,c.preferFlash=!1;za();c.html5.usingFlash=ya();q=c.html5.usingFlash;Ba(); 73 | if(!p&&q)c.flashLoadTimeout=1;h.removeEventListener&&h.removeEventListener("DOMContentLoaded",B,!1);Q();return!0};la=function(){h.readyState==="complete"&&(B(),h.detachEvent("onreadystatechange",la));return!0};X();k.add(i,"focus",x);k.add(i,"load",x);k.add(i,"load",P);L&&E&&k.add(i,"mousemove",x);h.addEventListener?h.addEventListener("DOMContentLoaded",B,!1):h.attachEvent?h.attachEvent("onreadystatechange",la):C({type:"NO_DOM2_EVENTS",fatal:!0});h.readyState==="complete"&&setTimeout(B,100)}var Y= 74 | null;if(typeof SM2_DEFER==="undefined"||!SM2_DEFER)Y=new M;Z.SoundManager=M;Z.soundManager=Y})(window); --------------------------------------------------------------------------------