typo 3.99.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/CHANGELOG +718 -0
- data/MAINTAINERS +30 -0
- data/MIT-LICENSE +21 -0
- data/README +92 -0
- data/Rakefile +10 -0
- data/app/apis/blogger_service.rb +94 -0
- data/app/apis/meta_weblog_service.rb +197 -0
- data/app/apis/movable_type_service.rb +150 -0
- data/app/apis/typo_web_service.rb +26 -0
- data/app/controllers/accounts_controller.rb +52 -0
- data/app/controllers/admin/base_controller.rb +21 -0
- data/app/controllers/admin/blacklist_controller.rb +50 -0
- data/app/controllers/admin/cache_controller.rb +31 -0
- data/app/controllers/admin/categories_controller.rb +64 -0
- data/app/controllers/admin/comments_controller.rb +57 -0
- data/app/controllers/admin/content_controller.rb +147 -0
- data/app/controllers/admin/general_controller.rb +42 -0
- data/app/controllers/admin/pages_controller.rb +50 -0
- data/app/controllers/admin/resources_controller.rb +98 -0
- data/app/controllers/admin/sidebar_controller.rb +74 -0
- data/app/controllers/admin/textfilters_controller.rb +104 -0
- data/app/controllers/admin/themes_controller.rb +20 -0
- data/app/controllers/admin/trackbacks_controller.rb +54 -0
- data/app/controllers/admin/users_controller.rb +41 -0
- data/app/controllers/application.rb +66 -0
- data/app/controllers/articles_controller.rb +218 -0
- data/app/controllers/backend_controller.rb +11 -0
- data/app/controllers/content_controller.rb +98 -0
- data/app/controllers/live_controller.rb +10 -0
- data/app/controllers/redirect_controller.rb +16 -0
- data/app/controllers/sidebar_controller.rb +50 -0
- data/app/controllers/textfilter_controller.rb +22 -0
- data/app/controllers/theme_controller.rb +52 -0
- data/app/controllers/xml_controller.rb +111 -0
- data/app/helpers/accounts_helper.rb +2 -0
- data/app/helpers/admin/base_helper.rb +124 -0
- data/app/helpers/admin/blacklist_helper.rb +2 -0
- data/app/helpers/admin/cache_helper.rb +2 -0
- data/app/helpers/admin/comments_helper.rb +2 -0
- data/app/helpers/admin/content_helper.rb +2 -0
- data/app/helpers/admin/general_helper.rb +2 -0
- data/app/helpers/admin/pages_helper.rb +2 -0
- data/app/helpers/admin/resources_helper.rb +2 -0
- data/app/helpers/admin/sidebar_helper.rb +2 -0
- data/app/helpers/admin/textfilters_helper.rb +2 -0
- data/app/helpers/admin/themes_helper.rb +2 -0
- data/app/helpers/admin/trackbacks_helper.rb +2 -0
- data/app/helpers/admin/users_helper.rb +2 -0
- data/app/helpers/application_helper.rb +92 -0
- data/app/helpers/articles_helper.rb +163 -0
- data/app/helpers/backend_helper.rb +2 -0
- data/app/helpers/content_helper.rb +3 -0
- data/app/helpers/mail_helper.rb +6 -0
- data/app/helpers/redirect_helper.rb +2 -0
- data/app/helpers/sidebar_helper.rb +22 -0
- data/app/helpers/sidebars/plugin_helper.rb +2 -0
- data/app/helpers/text_filter_plugin_helper.rb +2 -0
- data/app/helpers/textfilter_helper.rb +2 -0
- data/app/helpers/theme_helper.rb +23 -0
- data/app/helpers/xml_helper.rb +21 -0
- data/app/models/aggregations/audioscrobbler.rb +54 -0
- data/app/models/aggregations/backpack.rb +57 -0
- data/app/models/aggregations/delicious.rb +57 -0
- data/app/models/aggregations/flickr.rb +89 -0
- data/app/models/aggregations/fortythree.rb +62 -0
- data/app/models/aggregations/magnolia.rb +81 -0
- data/app/models/aggregations/tada.rb +75 -0
- data/app/models/aggregations/technorati.rb +51 -0
- data/app/models/aggregations/upcoming.rb +74 -0
- data/app/models/article.rb +211 -0
- data/app/models/blacklist_pattern.rb +22 -0
- data/app/models/blog.rb +162 -0
- data/app/models/blog_sweeper.rb +23 -0
- data/app/models/category.rb +62 -0
- data/app/models/comment.rb +76 -0
- data/app/models/config_manager.rb +80 -0
- data/app/models/content.rb +222 -0
- data/app/models/content_observer.rb +5 -0
- data/app/models/content_state/base.rb +51 -0
- data/app/models/content_state/draft.rb +40 -0
- data/app/models/content_state/factory.rb +16 -0
- data/app/models/content_state/just_published.rb +47 -0
- data/app/models/content_state/new.rb +45 -0
- data/app/models/content_state/publication_pending.rb +43 -0
- data/app/models/content_state/published.rb +35 -0
- data/app/models/email_notifier.rb +9 -0
- data/app/models/notification_mailer.rb +34 -0
- data/app/models/page.rb +20 -0
- data/app/models/page_cache.rb +29 -0
- data/app/models/ping.rb +129 -0
- data/app/models/redirect.rb +3 -0
- data/app/models/resource.rb +76 -0
- data/app/models/sidebar.rb +32 -0
- data/app/models/simple_cache.rb +37 -0
- data/app/models/tag.rb +63 -0
- data/app/models/text_filter.rb +111 -0
- data/app/models/theme.rb +44 -0
- data/app/models/trackback.rb +51 -0
- data/app/models/trigger.rb +31 -0
- data/app/models/user.rb +113 -0
- data/app/models/web_notifier.rb +7 -0
- data/app/views/accounts/login.rhtml +24 -0
- data/app/views/accounts/logout.rhtml +12 -0
- data/app/views/accounts/signup.rhtml +26 -0
- data/app/views/accounts/welcome.rhtml +13 -0
- data/app/views/admin/base/_recent_comments.rhtml +10 -0
- data/app/views/admin/base/_recent_trackbacks.rhtml +10 -0
- data/app/views/admin/blacklist/_blacklist_patterns.rhtml +16 -0
- data/app/views/admin/blacklist/_form.rhtml +15 -0
- data/app/views/admin/blacklist/_quick_post.rhtml +16 -0
- data/app/views/admin/blacklist/destroy.rhtml +10 -0
- data/app/views/admin/blacklist/edit.rhtml +14 -0
- data/app/views/admin/blacklist/list.rhtml +13 -0
- data/app/views/admin/cache/list.rhtml +8 -0
- data/app/views/admin/categories/_categories.rhtml +14 -0
- data/app/views/admin/categories/_form.rhtml +7 -0
- data/app/views/admin/categories/_quick_post.rhtml +11 -0
- data/app/views/admin/categories/destroy.rhtml +10 -0
- data/app/views/admin/categories/edit.rhtml +13 -0
- data/app/views/admin/categories/list.rhtml +15 -0
- data/app/views/admin/categories/reorder.rhtml +9 -0
- data/app/views/admin/categories/show.rhtml +18 -0
- data/app/views/admin/comments/_form.rhtml +19 -0
- data/app/views/admin/comments/comments.rhtml +4 -0
- data/app/views/admin/comments/destroy.rhtml +11 -0
- data/app/views/admin/comments/edit.rhtml +18 -0
- data/app/views/admin/comments/list.rhtml +31 -0
- data/app/views/admin/comments/new.rhtml +15 -0
- data/app/views/admin/comments/show.rhtml +10 -0
- data/app/views/admin/content/_articles.rhtml +20 -0
- data/app/views/admin/content/_attachment.rhtml +17 -0
- data/app/views/admin/content/_form.rhtml +51 -0
- data/app/views/admin/content/_pages.rhtml +3 -0
- data/app/views/admin/content/_quick_post.rhtml +20 -0
- data/app/views/admin/content/_show_categories.rhtml +9 -0
- data/app/views/admin/content/_show_resources.rhtml +9 -0
- data/app/views/admin/content/destroy.rhtml +11 -0
- data/app/views/admin/content/edit.rhtml +28 -0
- data/app/views/admin/content/list.rhtml +20 -0
- data/app/views/admin/content/new.rhtml +27 -0
- data/app/views/admin/content/preview.rhtml +3 -0
- data/app/views/admin/content/show.rhtml +25 -0
- data/app/views/admin/general/index.rhtml +216 -0
- data/app/views/admin/general/update_database.rhtml +44 -0
- data/app/views/admin/pages/_form.rhtml +19 -0
- data/app/views/admin/pages/_pages.rhtml +18 -0
- data/app/views/admin/pages/_quick_post.rhtml +21 -0
- data/app/views/admin/pages/destroy.rhtml +11 -0
- data/app/views/admin/pages/edit.rhtml +28 -0
- data/app/views/admin/pages/list.rhtml +13 -0
- data/app/views/admin/pages/new.rhtml +24 -0
- data/app/views/admin/pages/preview.rhtml +1 -0
- data/app/views/admin/pages/show.rhtml +14 -0
- data/app/views/admin/resources/_itunes_category_add.rhtml +11 -0
- data/app/views/admin/resources/_itunes_category_edit.rhtml +32 -0
- data/app/views/admin/resources/_metadata_add.rhtml +22 -0
- data/app/views/admin/resources/_metadata_edit.rhtml +22 -0
- data/app/views/admin/resources/_mime_edit.rhtml +8 -0
- data/app/views/admin/resources/_pages.rhtml +3 -0
- data/app/views/admin/resources/_resources.rhtml +40 -0
- data/app/views/admin/resources/destroy.rhtml +11 -0
- data/app/views/admin/resources/list.rhtml +9 -0
- data/app/views/admin/resources/new.rhtml +12 -0
- data/app/views/admin/sidebar/_active.rhtml +14 -0
- data/app/views/admin/sidebar/_actives.rhtml +9 -0
- data/app/views/admin/sidebar/_available.rhtml +5 -0
- data/app/views/admin/sidebar/_availables.rhtml +5 -0
- data/app/views/admin/sidebar/_publish.rhtml +2 -0
- data/app/views/admin/sidebar/_target.rhtml +1 -0
- data/app/views/admin/sidebar/index.rhtml +34 -0
- data/app/views/admin/sidebar/publish.rjs +6 -0
- data/app/views/admin/sidebar/remove.rjs +5 -0
- data/app/views/admin/sidebar/set_active.rjs +10 -0
- data/app/views/admin/textfilters/_form.rhtml +45 -0
- data/app/views/admin/textfilters/_macros.rhtml +16 -0
- data/app/views/admin/textfilters/_textfilters.rhtml +20 -0
- data/app/views/admin/textfilters/destroy.rhtml +10 -0
- data/app/views/admin/textfilters/edit.rhtml +17 -0
- data/app/views/admin/textfilters/list.rhtml +15 -0
- data/app/views/admin/textfilters/macro_help.rhtml +3 -0
- data/app/views/admin/textfilters/new.rhtml +15 -0
- data/app/views/admin/textfilters/preview.rhtml +3 -0
- data/app/views/admin/textfilters/show.rhtml +34 -0
- data/app/views/admin/textfilters/show_help.rhtml +8 -0
- data/app/views/admin/themes/index.rhtml +12 -0
- data/app/views/admin/trackbacks/_form.rhtml +19 -0
- data/app/views/admin/trackbacks/destroy.rhtml +6 -0
- data/app/views/admin/trackbacks/edit.rhtml +14 -0
- data/app/views/admin/trackbacks/list.rhtml +31 -0
- data/app/views/admin/trackbacks/new.rhtml +15 -0
- data/app/views/admin/trackbacks/show.rhtml +14 -0
- data/app/views/admin/users/_form.rhtml +48 -0
- data/app/views/admin/users/_user.rhtml +9 -0
- data/app/views/admin/users/destroy.rhtml +14 -0
- data/app/views/admin/users/edit.rhtml +14 -0
- data/app/views/admin/users/list.rhtml +9 -0
- data/app/views/admin/users/new.rhtml +15 -0
- data/app/views/admin/users/show.rhtml +18 -0
- data/app/views/articles/_article.rhtml +4 -0
- data/app/views/articles/_comment.rhtml +7 -0
- data/app/views/articles/_comment_box.rhtml +43 -0
- data/app/views/articles/_comment_error.rhtml +1 -0
- data/app/views/articles/_trackback.rhtml +7 -0
- data/app/views/articles/archives.rhtml +22 -0
- data/app/views/articles/comment_preview.rhtml +3 -0
- data/app/views/articles/error.rhtml +3 -0
- data/app/views/articles/groupings.rhtml +14 -0
- data/app/views/articles/index.rhtml +11 -0
- data/app/views/articles/read.rhtml +70 -0
- data/app/views/articles/trackback.rxml +5 -0
- data/app/views/articles/view_page.rhtml +3 -0
- data/app/views/layouts/accounts.rhtml +22 -0
- data/app/views/layouts/administration.rhtml +75 -0
- data/app/views/layouts/sidebar.rhtml +40 -0
- data/app/views/live/search.rhtml +10 -0
- data/app/views/notification_mailer/_mail_footer.rhtml +7 -0
- data/app/views/notification_mailer/_mail_header.rhtml +1 -0
- data/app/views/notification_mailer/article.rhtml +6 -0
- data/app/views/notification_mailer/comment.rhtml +11 -0
- data/app/views/notification_mailer/trackback.rhtml +3 -0
- data/app/views/settings/done.rhtml +2 -0
- data/app/views/settings/install.rhtml +12 -0
- data/app/views/shared/_search.rhtml +10 -0
- data/app/views/sidebar/_row.rhtml +1 -0
- data/app/views/sidebar/_sidebar.rhtml +5 -0
- data/app/views/sidebar/display_plugins.rhtml +5 -0
- data/app/views/sidebar/show.rhtml +1 -0
- data/app/views/theme/static_view_test.rhtml +1 -0
- data/app/views/xml/_atom10_item_article.rxml +39 -0
- data/app/views/xml/_atom10_item_comment.rxml +13 -0
- data/app/views/xml/_atom10_item_trackback.rxml +16 -0
- data/app/views/xml/_itunes_item_resource.rxml +30 -0
- data/app/views/xml/_rss20_item_article.rxml +35 -0
- data/app/views/xml/_rss20_item_comment.rxml +7 -0
- data/app/views/xml/_rss20_item_trackback.rxml +7 -0
- data/app/views/xml/atom10_feed.rxml +18 -0
- data/app/views/xml/itunes_feed.rxml +29 -0
- data/app/views/xml/rsd.rxml +19 -0
- data/app/views/xml/rss20_feed.rxml +18 -0
- data/bin/typo +12 -0
- data/cache/META/DATA/ACTION_PARAM/localhost.3000/articles/index/.cache +540 -0
- data/cache/META/DATA/ACTION_PARAM/localhost.3000/articles/permalink/day=09&month=09&title=i-need-a-new-keyboard-and-mouse&year=2005.cache +414 -0
- data/cache/META/META/ACTION_PARAM/localhost.3000/articles/index/.cache +3 -0
- data/cache/META/META/ACTION_PARAM/localhost.3000/articles/permalink/day=09&month=09&title=i-need-a-new-keyboard-and-mouse&year=2005.cache +3 -0
- data/components/plugins/sidebars/aimpresence/content.rhtml +4 -0
- data/components/plugins/sidebars/aimpresence_controller.rb +10 -0
- data/components/plugins/sidebars/amazon/content.rhtml +4 -0
- data/components/plugins/sidebars/amazon_controller.rb +17 -0
- data/components/plugins/sidebars/archives/content.rhtml +11 -0
- data/components/plugins/sidebars/archives_controller.rb +24 -0
- data/components/plugins/sidebars/audioscrobbler/content.rhtml +10 -0
- data/components/plugins/sidebars/audioscrobbler_controller.rb +10 -0
- data/components/plugins/sidebars/backpack/content.rhtml +12 -0
- data/components/plugins/sidebars/backpack_controller.rb +17 -0
- data/components/plugins/sidebars/category/content.rhtml +10 -0
- data/components/plugins/sidebars/category_controller.rb +13 -0
- data/components/plugins/sidebars/delicious/content.rhtml +20 -0
- data/components/plugins/sidebars/delicious_controller.rb +29 -0
- data/components/plugins/sidebars/flickr/content.rhtml +15 -0
- data/components/plugins/sidebars/flickr_controller.rb +16 -0
- data/components/plugins/sidebars/fortythree/content.rhtml +8 -0
- data/components/plugins/sidebars/fortythree_controller.rb +12 -0
- data/components/plugins/sidebars/fortythreeplaces/content.rhtml +8 -0
- data/components/plugins/sidebars/fortythreeplaces_controller.rb +12 -0
- data/components/plugins/sidebars/magnolia/content.rhtml +12 -0
- data/components/plugins/sidebars/magnolia_controller.rb +17 -0
- data/components/plugins/sidebars/recent_comments/content.rhtml +12 -0
- data/components/plugins/sidebars/recent_comments_controller.rb +23 -0
- data/components/plugins/sidebars/static/content.rhtml +2 -0
- data/components/plugins/sidebars/static_controller.rb +23 -0
- data/components/plugins/sidebars/tada/content.rhtml +12 -0
- data/components/plugins/sidebars/tada_controller.rb +12 -0
- data/components/plugins/sidebars/tag/content.rhtml +8 -0
- data/components/plugins/sidebars/tag_controller.rb +18 -0
- data/components/plugins/sidebars/technorati/content.rhtml +8 -0
- data/components/plugins/sidebars/technorati_controller.rb +12 -0
- data/components/plugins/sidebars/upcoming/content.rhtml +8 -0
- data/components/plugins/sidebars/upcoming_controller.rb +11 -0
- data/components/plugins/sidebars/xbox/content.rhtml +2 -0
- data/components/plugins/sidebars/xbox_controller.rb +6 -0
- data/components/plugins/sidebars/xml/content.rhtml +12 -0
- data/components/plugins/sidebars/xml_controller.rb +11 -0
- data/components/plugins/textfilters/amazon_controller.rb +39 -0
- data/components/plugins/textfilters/code_controller.rb +59 -0
- data/components/plugins/textfilters/flickr_controller.rb +75 -0
- data/components/plugins/textfilters/htmlfilter_controller.rb +8 -0
- data/components/plugins/textfilters/lightbox_controller.rb +122 -0
- data/components/plugins/textfilters/macropost_controller.rb +14 -0
- data/components/plugins/textfilters/macropre_controller.rb +14 -0
- data/components/plugins/textfilters/markdown_controller.rb +32 -0
- data/components/plugins/textfilters/none_controller.rb +8 -0
- data/components/plugins/textfilters/smartypants_controller.rb +8 -0
- data/components/plugins/textfilters/sparkline_controller.rb +87 -0
- data/components/plugins/textfilters/textile_controller.rb +8 -0
- data/components/sidebars/README +36 -0
- data/config/boot.rb +44 -0
- data/config/database.yml +17 -0
- data/config/database.yml-pgsql +17 -0
- data/config/database.yml.example +18 -0
- data/config/environment.rb +145 -0
- data/config/environments/development.rb +17 -0
- data/config/environments/production.rb +19 -0
- data/config/environments/test.rb +26 -0
- data/config/iTunes.yml +72 -0
- data/config/lighttpd.conf +46 -0
- data/config/mail.yml +8 -0
- data/config/mail.yml.example +8 -0
- data/config/routes.rb +92 -0
- data/db/DB +0 -0
- data/db/DB.test +0 -0
- data/db/converters/README +14 -0
- data/db/converters/feed.rb +68 -0
- data/db/converters/mt-import.rb +72 -0
- data/db/converters/mt3.rb +172 -0
- data/db/converters/rss.rb +67 -0
- data/db/converters/s9y.rb +182 -0
- data/db/converters/textpattern.rb +137 -0
- data/db/converters/wordpress.rb +187 -0
- data/db/development_structure.sql +691 -0
- data/db/migrate/001_initial_schema.rb +127 -0
- data/db/migrate/002_add_user_email.rb +17 -0
- data/db/migrate/003_add_article_user_id.rb +20 -0
- data/db/migrate/004_add_sidebars.rb +31 -0
- data/db/migrate/005_add_cache_table.rb +20 -0
- data/db/migrate/006_add_pages.rb +17 -0
- data/db/migrate/007_add_permalink.rb +36 -0
- data/db/migrate/008_add_page_title.rb +9 -0
- data/db/migrate/009_add_article_guid.rb +10 -0
- data/db/migrate/010_add_tags.rb +19 -0
- data/db/migrate/011_add_article_id.rb +17 -0
- data/db/migrate/012_enlarge_settings.rb +11 -0
- data/db/migrate/013_add_textfilters.rb +33 -0
- data/db/migrate/014_move_text_filter_to_text_filter_id.rb +43 -0
- data/db/migrate/015_convert_mysql_to_innodb.rb +19 -0
- data/db/migrate/016_fix_is_primary_postgres.rb +19 -0
- data/db/migrate/017_add_comment_user_id.rb +23 -0
- data/db/migrate/018_add_guids.rb +13 -0
- data/db/migrate/019_add_whiteboards_to_content.rb +15 -0
- data/db/migrate/020_superclass_articles.rb +167 -0
- data/db/migrate/021_superclass_comments.rb +94 -0
- data/db/migrate/022_superclass_trackbacks.rb +71 -0
- data/db/migrate/023_superclass_pages.rb +64 -0
- data/db/migrate/024_cleanup_contents.rb +54 -0
- data/db/migrate/025_add_itunes_metadata.rb +29 -0
- data/db/migrate/026_add_redirect_table.rb +13 -0
- data/db/migrate/027_set_comment_published_flag.rb +19 -0
- data/db/migrate/028_rename_redirect_to.rb +12 -0
- data/db/migrate/029_add_user_notification.rb +29 -0
- data/db/migrate/030_index_sessions.rb +9 -0
- data/db/migrate/031_add_notifications_table.rb +14 -0
- data/db/migrate/032_add_jabber_notification.rb +11 -0
- data/db/migrate/033_add_count_caching.rb +34 -0
- data/db/migrate/034_boolify_published.rb +36 -0
- data/db/migrate/035_boolify_content_allow_foo.rb +36 -0
- data/db/migrate/036_add_tag_display_name.rb +53 -0
- data/db/migrate/037_enlarge_ip_field.rb +9 -0
- data/db/migrate/038_add_blog_object.rb +52 -0
- data/db/migrate/039_serialize_blog_attributes.rb +160 -0
- data/db/migrate/040_attach_content_to_blog.rb +28 -0
- data/db/migrate/041_fixup_default_sidebars.rb +18 -0
- data/db/migrate/042_remove_sidebar_staged_config.rb +22 -0
- data/db/migrate/043_create_triggers.rb +14 -0
- data/db/migrate/044_add_published_at_to_content.rb +18 -0
- data/db/migrate/045_fix_contents_published_default.rb +9 -0
- data/db/migrate/046_fixup_forthcoming_publications.rb +40 -0
- data/db/schema.mysql-v3.sql +218 -0
- data/db/schema.mysql.sql +218 -0
- data/db/schema.postgresql.sql +218 -0
- data/db/schema.rb +169 -0
- data/db/schema.sqlite.sql +218 -0
- data/db/schema.sqlserver.sql +232 -0
- data/db/schema_version +1 -0
- data/db/scripts/fix_permalinks.rb +5 -0
- data/db/updates/update.168.to.200.mysql.sql +33 -0
- data/db/updates/update.168.to.200.psql.sql +30 -0
- data/doc/Installer.txt +55 -0
- data/doc/README_FOR_APP +2 -0
- data/installer/rails-installer.rb +488 -0
- data/installer/rails_installer_defaults.yml +4 -0
- data/installer/typo-installer.rb +35 -0
- data/lib/backpack_api.rb +202 -0
- data/lib/bare_migration.rb +142 -0
- data/lib/email_notify.rb +32 -0
- data/lib/format.rb +19 -0
- data/lib/generators/sidebar/sidebar_generator.rb +13 -0
- data/lib/generators/sidebar/templates/components/plugins/sidebars/controller_template.rb +20 -0
- data/lib/generators/sidebar/templates/components/plugins/sidebars/views/content_template.rhtml +4 -0
- data/lib/jabber_notify.rb +32 -0
- data/lib/login_system.rb +85 -0
- data/lib/migrator.rb +28 -0
- data/lib/rails_patch/active_record.rb +36 -0
- data/lib/rails_patch/components.rb +14 -0
- data/lib/sidebars/component_plugin.rb +5 -0
- data/lib/sidebars/plugin.rb +241 -0
- data/lib/spam_protection.rb +126 -0
- data/lib/tasks/release.rake +171 -0
- data/lib/tasks/schemas.rake +6 -0
- data/lib/tasks/sweep_cache.rake +6 -0
- data/lib/text_filter_plugin.rb +97 -0
- data/lib/transforms.rb +26 -0
- data/lib/typo_guid.rb +10 -0
- data/lib/typo_plugins.rb +19 -0
- data/lib/typo_version.rb +1 -0
- data/lib/xmlrpc_fix.rb +13 -0
- data/public/.htaccess +34 -0
- data/public/404.html +8 -0
- data/public/500.html +8 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +24 -0
- data/public/dispatch.rb +10 -0
- data/public/favicon.ico +0 -0
- data/public/images/admin/dot-vertical.gif +0 -0
- data/public/images/admin/h-tile.gif +0 -0
- data/public/images/admin/hdr-tile.gif +0 -0
- data/public/images/admin/toggle.gif +0 -0
- data/public/images/bg.jpg +0 -0
- data/public/images/bgcolor.jpg +0 -0
- data/public/images/body_bg.png +0 -0
- data/public/images/branding_bg.png +0 -0
- data/public/images/branding_logo.png +0 -0
- data/public/images/checked.gif +0 -0
- data/public/images/content_bg.png +0 -0
- data/public/images/delete.png +0 -0
- data/public/images/footer.jpg +0 -0
- data/public/images/footer.png +0 -0
- data/public/images/global_bg.png +0 -0
- data/public/images/global_logo.png +0 -0
- data/public/images/go.png +0 -0
- data/public/images/header.jpg +0 -0
- data/public/images/loading.gif +0 -0
- data/public/images/not-checked copy.gif +0 -0
- data/public/images/not-checked.gif +0 -0
- data/public/images/overlay.png +0 -0
- data/public/images/powered.gif +0 -0
- data/public/images/section_bg.png +0 -0
- data/public/images/sections_bg.png +0 -0
- data/public/images/sections_hilite.png +0 -0
- data/public/images/sections_hover.png +0 -0
- data/public/images/spinner-blue.gif +0 -0
- data/public/images/spinner.gif +0 -0
- data/public/images/spot-header.gif +0 -0
- data/public/images/spot-title.gif +0 -0
- data/public/images/x-ed.gif +0 -0
- data/public/javascripts/application.js +2 -0
- data/public/javascripts/controls.js +815 -0
- data/public/javascripts/cookies.js +60 -0
- data/public/javascripts/dragdrop.js +724 -0
- data/public/javascripts/effects.js +953 -0
- data/public/javascripts/lightbox.js +348 -0
- data/public/javascripts/prototype.js +1985 -0
- data/public/javascripts/scriptaculous.js +47 -0
- data/public/javascripts/slider.js +258 -0
- data/public/javascripts/typo.js +85 -0
- data/public/robots.txt +2 -0
- data/public/stylesheets/administration.css +585 -0
- data/public/stylesheets/lightbox.css +22 -0
- data/public/stylesheets/rss.css +54 -0
- data/public/stylesheets/user-styles.css +0 -0
- data/script/about +3 -0
- data/script/benchmarker +19 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/lighttpd +2 -0
- data/script/logreport +79 -0
- data/script/migrate +31 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/process/spinner +3 -0
- data/script/profiler +34 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/script/spacecheck +40 -0
- data/test/fixtures/articles_categories.yml +31 -0
- data/test/fixtures/articles_tags.yml +19 -0
- data/test/fixtures/blacklist_patterns.yml +10 -0
- data/test/fixtures/blogs.yml +74 -0
- data/test/fixtures/categories.yml +35 -0
- data/test/fixtures/contents.yml +297 -0
- data/test/fixtures/notification_mailer/article +3 -0
- data/test/fixtures/notification_mailer/comment +3 -0
- data/test/fixtures/notification_mailer/trackback +3 -0
- data/test/fixtures/notifications.yml +0 -0
- data/test/fixtures/page_caches.yml +7 -0
- data/test/fixtures/redirects.yml +13 -0
- data/test/fixtures/resources.yml +24 -0
- data/test/fixtures/sidebars.yml +5 -0
- data/test/fixtures/tags.yml +13 -0
- data/test/fixtures/text_filters.yml +42 -0
- data/test/fixtures/triggers.yml +1 -0
- data/test/fixtures/users.yml +56 -0
- data/test/functional/accounts_controller_test.rb +82 -0
- data/test/functional/admin/article_preview_test.rb +67 -0
- data/test/functional/admin/blacklist_controller_test.rb +63 -0
- data/test/functional/admin/categories_controller_test.rb +112 -0
- data/test/functional/admin/comments_controller_test.rb +78 -0
- data/test/functional/admin/content_controller_test.rb +234 -0
- data/test/functional/admin/general_controller_test.rb +26 -0
- data/test/functional/admin/pages_controller_test.rb +103 -0
- data/test/functional/admin/resources_controller_test.rb +49 -0
- data/test/functional/admin/textfilters_controller_test.rb +29 -0
- data/test/functional/admin/themes_controller_test.rb +34 -0
- data/test/functional/admin/trackbacks_controller_test.rb +76 -0
- data/test/functional/admin/users_controller_test.rb +72 -0
- data/test/functional/articles_controller_test.rb +525 -0
- data/test/functional/backend_controller_test.rb +273 -0
- data/test/functional/redirect_controller_test.rb +40 -0
- data/test/functional/textfilter_controller_test.rb +275 -0
- data/test/functional/theme_controller_test.rb +45 -0
- data/test/functional/xml_controller_test.rb +353 -0
- data/test/mocks/test/dns_mock.rb +13 -0
- data/test/mocks/test/flickr_mock.rb +30 -0
- data/test/mocks/test/http_mock.rb +38 -0
- data/test/mocks/test/theme_mock.rb +5 -0
- data/test/mocks/test/xmlrpc_mock.rb +27 -0
- data/test/mocks/themes/123-numbers-in-path/about.markdown +0 -0
- data/test/mocks/themes/CamelCaseDirectory/about.markdown +0 -0
- data/test/mocks/themes/azure/about.markdown +5 -0
- data/test/mocks/themes/azure/layouts/default.rhtml +50 -0
- data/test/mocks/themes/azure/preview.png +0 -0
- data/test/mocks/themes/azure/views/theme/static_view_test.rhtml +1 -0
- data/test/mocks/themes/i-have-special-chars/about.markdown +0 -0
- data/test/test_helper.rb +95 -0
- data/test/unit/article_test.rb +245 -0
- data/test/unit/assumptions_tests.rb +54 -0
- data/test/unit/audioscrobbler_test.rb +132 -0
- data/test/unit/blacklist_pattern_test.rb +14 -0
- data/test/unit/blog_test.rb +83 -0
- data/test/unit/category_test.rb +37 -0
- data/test/unit/comment_test.rb +117 -0
- data/test/unit/configuration_test.rb +21 -0
- data/test/unit/content_state/factory_test.rb +84 -0
- data/test/unit/delicious_test.rb +96 -0
- data/test/unit/flickr_test.rb +134 -0
- data/test/unit/fortythree_test.rb +66 -0
- data/test/unit/magnolia_test.rb +87 -0
- data/test/unit/metafragment_test.rb +63 -0
- data/test/unit/notification_mailer_test.rb +55 -0
- data/test/unit/observer_test.rb +40 -0
- data/test/unit/page_cache_test.rb +34 -0
- data/test/unit/page_test.rb +25 -0
- data/test/unit/ping_test.rb +111 -0
- data/test/unit/redirect_test.rb +19 -0
- data/test/unit/resource_test.rb +71 -0
- data/test/unit/sidebar_test.rb +14 -0
- data/test/unit/tag_test.rb +66 -0
- data/test/unit/text_filter_test.rb +126 -0
- data/test/unit/theme_test.rb +44 -0
- data/test/unit/trackback_test.rb +45 -0
- data/test/unit/trigger_test.rb +40 -0
- data/test/unit/user_test.rb +111 -0
- data/themes/azure/about.markdown +5 -0
- data/themes/azure/images/bg-tile.gif +0 -0
- data/themes/azure/images/bracket.gif +0 -0
- data/themes/azure/images/bullet.gif +0 -0
- data/themes/azure/images/hdr.gif +0 -0
- data/themes/azure/images/q-close.gif +0 -0
- data/themes/azure/images/q-open.gif +0 -0
- data/themes/azure/images/sbar-tile.gif +0 -0
- data/themes/azure/images/spinner.gif +0 -0
- data/themes/azure/images/xlink.gif +0 -0
- data/themes/azure/layouts/default.rhtml +50 -0
- data/themes/azure/preview.png +0 -0
- data/themes/azure/stylesheets/azure.css +436 -0
- data/themes/azure/stylesheets/print.css +30 -0
- data/themes/azure/views/theme/static_view_test.rhtml +1 -0
- data/vendor/akismet/Akismet.rb +140 -0
- data/vendor/bluecloth/CHANGES +366 -0
- data/vendor/bluecloth/LICENSE +340 -0
- data/vendor/bluecloth/README +99 -0
- data/vendor/bluecloth/bin/bluecloth +83 -0
- data/vendor/bluecloth/install.rb +150 -0
- data/vendor/bluecloth/lib/bluecloth.rb +1144 -0
- data/vendor/bluecloth/test.rb +117 -0
- data/vendor/bluecloth/tests/00_Class.tests.rb +71 -0
- data/vendor/bluecloth/tests/05_Markdown.tests.rb +1527 -0
- data/vendor/bluecloth/tests/10_Bug.tests.rb +57 -0
- data/vendor/bluecloth/tests/15_Contrib.tests.rb +132 -0
- data/vendor/bluecloth/tests/bctestcase.rb +274 -0
- data/vendor/bluecloth/tests/data/antsugar.txt +34 -0
- data/vendor/bluecloth/tests/data/ml-announce.txt +17 -0
- data/vendor/bluecloth/tests/data/re-overflow.txt +67 -0
- data/vendor/bluecloth/tests/data/re-overflow2.txt +281 -0
- data/vendor/bluecloth/utils.rb +553 -0
- data/vendor/flickr/Rakefile +36 -0
- data/vendor/flickr/flickr.rb +490 -0
- data/vendor/flickr/index.html +129 -0
- data/vendor/flickr/test_flickr.rb +173 -0
- data/vendor/jabber4r/CHANGES +8 -0
- data/vendor/jabber4r/LICENSE.txt +12 -0
- data/vendor/jabber4r/README +180 -0
- data/vendor/jabber4r/Rakefile.rb +143 -0
- data/vendor/jabber4r/lib/jabber4r/jabber4r.rb +22 -0
- data/vendor/jabber4r/lib/jabber4r/jid.rb +93 -0
- data/vendor/jabber4r/lib/jabber4r/protocol.rb +1384 -0
- data/vendor/jabber4r/lib/jabber4r/rexml_1.8_patch.rb +16 -0
- data/vendor/jabber4r/lib/jabber4r/roster.rb +322 -0
- data/vendor/jabber4r/lib/jabber4r/session.rb +615 -0
- data/vendor/jabber4r/lib/jabber4r/vcard.rb +42 -0
- data/vendor/plugins/expiring_action_cache/init.rb +2 -0
- data/vendor/plugins/expiring_action_cache/lib/actionparamcache.rb +113 -0
- data/vendor/plugins/expiring_action_cache/lib/metafragment.rb +46 -0
- data/vendor/plugins/upload_progress/CHANGELOG +3 -0
- data/vendor/plugins/upload_progress/MIT-LICENSE +20 -0
- data/vendor/plugins/upload_progress/README +45 -0
- data/vendor/plugins/upload_progress/Rakefile +23 -0
- data/vendor/plugins/upload_progress/init.rb +7 -0
- data/vendor/plugins/upload_progress/lib/multipart_progress.rb +169 -0
- data/vendor/plugins/upload_progress/lib/progress.rb +145 -0
- data/vendor/plugins/upload_progress/lib/upload_progress.rb +303 -0
- data/vendor/plugins/upload_progress/lib/upload_progress_helper.rb +424 -0
- data/vendor/plugins/upload_progress/public/stylesheets/upload_progress.css +21 -0
- data/vendor/plugins/upload_progress/test/multipart_progress_testx.rb +364 -0
- data/vendor/plugins/upload_progress/test/upload_progress_helper_testx.rb +134 -0
- data/vendor/plugins/upload_progress/test/upload_progress_testx.rb +88 -0
- data/vendor/redcloth/RedCloth.gemspec +52 -0
- data/vendor/redcloth/bin/redcloth +3 -0
- data/vendor/redcloth/doc/CHANGELOG +160 -0
- data/vendor/redcloth/doc/COPYING +25 -0
- data/vendor/redcloth/doc/README +106 -0
- data/vendor/redcloth/doc/REFERENCE +216 -0
- data/vendor/redcloth/doc/make.rb +359 -0
- data/vendor/redcloth/install.rb +1032 -0
- data/vendor/redcloth/lib/redcloth.rb +1130 -0
- data/vendor/redcloth/run-tests.rb +28 -0
- data/vendor/redcloth/setup.rb +1376 -0
- data/vendor/redcloth/tests/code.yml +105 -0
- data/vendor/redcloth/tests/hard_breaks.yml +26 -0
- data/vendor/redcloth/tests/images.yml +171 -0
- data/vendor/redcloth/tests/instiki.yml +39 -0
- data/vendor/redcloth/tests/links.yml +155 -0
- data/vendor/redcloth/tests/lists.yml +77 -0
- data/vendor/redcloth/tests/markdown.yml +218 -0
- data/vendor/redcloth/tests/poignant.yml +64 -0
- data/vendor/redcloth/tests/table.yml +198 -0
- data/vendor/redcloth/tests/textism.yml +406 -0
- data/vendor/ruby-mp3info/lib/mp3info.rb +720 -0
- data/vendor/rubypants/README +114 -0
- data/vendor/rubypants/Rakefile +55 -0
- data/vendor/rubypants/html/classes/RubyPants.html +924 -0
- data/vendor/rubypants/html/created.rid +1 -0
- data/vendor/rubypants/html/files/README.html +248 -0
- data/vendor/rubypants/html/files/rubypants_rb.html +125 -0
- data/vendor/rubypants/html/fr_class_index.html +27 -0
- data/vendor/rubypants/html/fr_file_index.html +28 -0
- data/vendor/rubypants/html/fr_method_index.html +38 -0
- data/vendor/rubypants/html/index.html +24 -0
- data/vendor/rubypants/html/rdoc-style.css +172 -0
- data/vendor/rubypants/install.rb +9 -0
- data/vendor/rubypants/rubypants.rb +490 -0
- data/vendor/rubypants/test_rubypants.rb +162 -0
- data/vendor/sparklines/README.txt +47 -0
- data/vendor/sparklines/USAGE +14 -0
- data/vendor/sparklines/lib/sparklines.rb +435 -0
- data/vendor/sparklines/samples/sparklinestest.rb +26 -0
- data/vendor/sparklines/sparklines_generator.rb +9 -0
- data/vendor/sparklines/templates/sparklines_controller.rb +30 -0
- data/vendor/sparklines/templates/sparklines_helper.rb +30 -0
- data/vendor/syntax/LICENSE +27 -0
- data/vendor/syntax/NEWS +16 -0
- data/vendor/syntax/README +38 -0
- data/vendor/syntax/Rakefile +194 -0
- data/vendor/syntax/api/classes/Syntax.html +173 -0
- data/vendor/syntax/api/classes/Syntax/Convertors.html +91 -0
- data/vendor/syntax/api/classes/Syntax/Convertors/Abstract.html +159 -0
- data/vendor/syntax/api/classes/Syntax/Convertors/HTML.html +149 -0
- data/vendor/syntax/api/classes/Syntax/Default.html +123 -0
- data/vendor/syntax/api/classes/Syntax/Ruby.html +319 -0
- data/vendor/syntax/api/classes/Syntax/Token.html +151 -0
- data/vendor/syntax/api/classes/Syntax/Tokenizer.html +324 -0
- data/vendor/syntax/api/classes/Syntax/Version.html +109 -0
- data/vendor/syntax/api/classes/Syntax/XML.html +205 -0
- data/vendor/syntax/api/classes/Syntax/YAML.html +189 -0
- data/vendor/syntax/api/created.rid +1 -0
- data/vendor/syntax/api/files/README.html +155 -0
- data/vendor/syntax/api/files/lib/syntax/common_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/convertors/abstract_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/convertors/html_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/lang/ruby_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/lang/xml_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/lang/yaml_rb.html +96 -0
- data/vendor/syntax/api/files/lib/syntax/version_rb.html +92 -0
- data/vendor/syntax/api/files/lib/syntax_rb.html +96 -0
- data/vendor/syntax/api/fr_class_index.html +56 -0
- data/vendor/syntax/api/fr_file_index.html +54 -0
- data/vendor/syntax/api/fr_method_index.html +65 -0
- data/vendor/syntax/api/index.html +26 -0
- data/vendor/syntax/api/rdoc-style.css +175 -0
- data/vendor/syntax/doc/manual-html/chapter-1.html +198 -0
- data/vendor/syntax/doc/manual-html/chapter-2.html +262 -0
- data/vendor/syntax/doc/manual-html/chapter-3.html +266 -0
- data/vendor/syntax/doc/manual-html/chapter-4.html +267 -0
- data/vendor/syntax/doc/manual-html/index.html +152 -0
- data/vendor/syntax/doc/manual-html/stylesheets/manual.css +270 -0
- data/vendor/syntax/doc/manual-html/stylesheets/ruby.css +17 -0
- data/vendor/syntax/doc/manual/chapter.erb +38 -0
- data/vendor/syntax/doc/manual/example.erb +18 -0
- data/vendor/syntax/doc/manual/index.erb +29 -0
- data/vendor/syntax/doc/manual/manual.rb +311 -0
- data/vendor/syntax/doc/manual/manual.yml +43 -0
- data/vendor/syntax/doc/manual/page.erb +87 -0
- data/vendor/syntax/doc/manual/parts/0000.txt +5 -0
- data/vendor/syntax/doc/manual/parts/0001.txt +16 -0
- data/vendor/syntax/doc/manual/parts/0002.txt +24 -0
- data/vendor/syntax/doc/manual/parts/0003.txt +6 -0
- data/vendor/syntax/doc/manual/parts/0004.txt +32 -0
- data/vendor/syntax/doc/manual/parts/0005.txt +18 -0
- data/vendor/syntax/doc/manual/parts/0006.txt +62 -0
- data/vendor/syntax/doc/manual/parts/0007.txt +3 -0
- data/vendor/syntax/doc/manual/parts/0008.txt +5 -0
- data/vendor/syntax/doc/manual/parts/0009.txt +29 -0
- data/vendor/syntax/doc/manual/parts/0010.txt +21 -0
- data/vendor/syntax/doc/manual/stylesheets/manual.css +270 -0
- data/vendor/syntax/doc/manual/stylesheets/ruby.css +17 -0
- data/vendor/syntax/doc/manual/tutorial.erb +30 -0
- data/vendor/syntax/lib/syntax.rb +38 -0
- data/vendor/syntax/lib/syntax/common.rb +163 -0
- data/vendor/syntax/lib/syntax/convertors/abstract.rb +27 -0
- data/vendor/syntax/lib/syntax/convertors/html.rb +51 -0
- data/vendor/syntax/lib/syntax/lang/ruby.rb +317 -0
- data/vendor/syntax/lib/syntax/lang/xml.rb +108 -0
- data/vendor/syntax/lib/syntax/lang/yaml.rb +105 -0
- data/vendor/syntax/lib/syntax/version.rb +9 -0
- data/vendor/syntax/setup.rb +1331 -0
- data/vendor/syntax/syntax.gemspec +24 -0
- data/vendor/syntax/test/ALL-TESTS.rb +5 -0
- data/vendor/syntax/test/syntax/tc_ruby.rb +871 -0
- data/vendor/syntax/test/syntax/tc_xml.rb +202 -0
- data/vendor/syntax/test/syntax/tc_yaml.rb +228 -0
- data/vendor/syntax/test/syntax/tokenizer_testcase.rb +40 -0
- data/vendor/syntax/test/tc_syntax.rb +22 -0
- data/vendor/uuidtools/CHANGELOG +4 -0
- data/vendor/uuidtools/README +13 -0
- data/vendor/uuidtools/install.rb +30 -0
- data/vendor/uuidtools/lib/uuidtools.rb +555 -0
- data/vendor/uuidtools/rakefile +112 -0
- metadata +1022 -0
@@ -0,0 +1,406 @@
|
|
1
|
+
---
|
2
|
+
in: h1. Header 1
|
3
|
+
out: <h1>Header 1</h1>
|
4
|
+
---
|
5
|
+
in: h2. Header 2
|
6
|
+
out: <h2>Header 2</h2>
|
7
|
+
---
|
8
|
+
in: h3. Header 3
|
9
|
+
out: <h3>Header 3</h3>
|
10
|
+
---
|
11
|
+
in: |-
|
12
|
+
Any old text.
|
13
|
+
|
14
|
+
bq. A block quotation.
|
15
|
+
|
16
|
+
Any old text.
|
17
|
+
|
18
|
+
out: |-
|
19
|
+
<p>Any old text.</p>
|
20
|
+
|
21
|
+
<blockquote>
|
22
|
+
<p>A block quotation.</p>
|
23
|
+
</blockquote>
|
24
|
+
|
25
|
+
<p>Any old text.</p>
|
26
|
+
|
27
|
+
---
|
28
|
+
in: This is covered elsewhere[1].
|
29
|
+
out: <p>This is covered elsewhere<sup><a href="#fn1">1</a></sup>.</p>
|
30
|
+
---
|
31
|
+
in: fn1. Down here, in fact.
|
32
|
+
out: <p id="fn1"><sup>1</sup> Down here, in fact.</p>
|
33
|
+
---
|
34
|
+
in: |-
|
35
|
+
# A first item
|
36
|
+
# A second item
|
37
|
+
# A third item
|
38
|
+
# A fourth item
|
39
|
+
out: |-
|
40
|
+
<ol>
|
41
|
+
<li>A first item</li>
|
42
|
+
<li>A second item</li>
|
43
|
+
<li>A third item</li>
|
44
|
+
<li>A fourth item</li>
|
45
|
+
</ol>
|
46
|
+
---
|
47
|
+
in: |-
|
48
|
+
* A first item
|
49
|
+
* A second item
|
50
|
+
* A third item
|
51
|
+
* A fourth item
|
52
|
+
|
53
|
+
out: |-
|
54
|
+
<ul>
|
55
|
+
<li>A first item</li>
|
56
|
+
<li>A second item</li>
|
57
|
+
<li>A third item</li>
|
58
|
+
<li>A fourth item</li>
|
59
|
+
</ul>
|
60
|
+
|
61
|
+
---
|
62
|
+
in: _a phrase_
|
63
|
+
out: <p><em>a phrase</em></p>
|
64
|
+
---
|
65
|
+
in: __a phrase__
|
66
|
+
out: <p><i>a phrase</i></p>
|
67
|
+
---
|
68
|
+
in: '*a phrase*'
|
69
|
+
out: <p><strong>a phrase</strong></p>
|
70
|
+
---
|
71
|
+
in: '**a phrase**'
|
72
|
+
out: <p><b>a phrase</b></p>
|
73
|
+
---
|
74
|
+
in: '*(a)* a'
|
75
|
+
out: <p><strong>(a)</strong> a</p>
|
76
|
+
---
|
77
|
+
in: '*(a)* *'
|
78
|
+
out: <p><strong>(a)</strong> *</p>
|
79
|
+
---
|
80
|
+
in: Nabokov's ??Pnin??
|
81
|
+
out: <p>Nabokov’s <cite>Pnin</cite></p>
|
82
|
+
---
|
83
|
+
in: -a phrase-
|
84
|
+
out: <p><del>a phrase</del></p>
|
85
|
+
---
|
86
|
+
in: +a phrase+
|
87
|
+
out: <p><ins>a phrase</ins></p>
|
88
|
+
---
|
89
|
+
in: ^a phrase^
|
90
|
+
out: <p><sup>a phrase</sup></p>
|
91
|
+
---
|
92
|
+
in: ~a phrase~
|
93
|
+
out: <p><sub>a phrase</sub></p>
|
94
|
+
# ---
|
95
|
+
# in: %(caps)SPAN%
|
96
|
+
# out: <p><span class="caps">SPAN</span>
|
97
|
+
---
|
98
|
+
in: %{color:red}red%
|
99
|
+
out: <p><span style="color:red;">red</span></p>
|
100
|
+
---
|
101
|
+
in: %[fr]rouge%
|
102
|
+
out: <p><span lang="fr">rouge</span></p>
|
103
|
+
---
|
104
|
+
in: _(big)red_
|
105
|
+
out: <p><em class="big">red</em></p>
|
106
|
+
---
|
107
|
+
in: p(bob). A paragraph
|
108
|
+
out: <p class="bob">A paragraph</p>
|
109
|
+
---
|
110
|
+
in: p{color:#ddd}. A paragraph
|
111
|
+
out: <p style="color:#ddd;">A paragraph</p>
|
112
|
+
---
|
113
|
+
in: p[fr]. A paragraph
|
114
|
+
out: <p lang="fr">A paragraph</p>
|
115
|
+
---
|
116
|
+
in: h2()>. right-aligned header2, indented 1em both side
|
117
|
+
out: <h2 style="padding-left:1em;padding-right:1em;text-align:right;">right-aligned header2, indented 1em both side</h2>
|
118
|
+
---
|
119
|
+
in: h3=. centered header
|
120
|
+
out: <h3 style="text-align:center;">centered header</h3>
|
121
|
+
---
|
122
|
+
in: '!>/image.gif! right-aligned image'
|
123
|
+
out: <p style="float:right"><img src="/image.gif" alt="" /> right-aligned image</p>
|
124
|
+
---
|
125
|
+
in: p[no]{color:red}. A Norse of a different colour.
|
126
|
+
out: <p style="color:red;" lang="no">A Norse of a different colour.</p>
|
127
|
+
---
|
128
|
+
in: |-
|
129
|
+
|This|is|a|simple|table|
|
130
|
+
|This|is|a|simple|row|
|
131
|
+
out: |-
|
132
|
+
<table>
|
133
|
+
<tr>
|
134
|
+
<td>This</td>
|
135
|
+
<td>is</td>
|
136
|
+
<td>a</td>
|
137
|
+
<td>simple</td>
|
138
|
+
<td>table</td>
|
139
|
+
</tr>
|
140
|
+
<tr>
|
141
|
+
<td>This</td>
|
142
|
+
<td>is</td>
|
143
|
+
<td>a</td>
|
144
|
+
<td>simple</td>
|
145
|
+
<td>row</td>
|
146
|
+
</tr>
|
147
|
+
</table>
|
148
|
+
---
|
149
|
+
in: |-
|
150
|
+
table{border:1px solid black}.
|
151
|
+
|This|is|a|row|
|
152
|
+
|This|is|a|row|
|
153
|
+
out: |-
|
154
|
+
<table style="border:1px solid black;">
|
155
|
+
<tr>
|
156
|
+
<td>This</td>
|
157
|
+
<td>is</td>
|
158
|
+
<td>a</td>
|
159
|
+
<td>row</td>
|
160
|
+
</tr>
|
161
|
+
<tr>
|
162
|
+
<td>This</td>
|
163
|
+
<td>is</td>
|
164
|
+
<td>a</td>
|
165
|
+
<td>row</td>
|
166
|
+
</tr>
|
167
|
+
</table>
|
168
|
+
---
|
169
|
+
in: '{background:#ddd}. |This|is|a|row|'
|
170
|
+
out: |-
|
171
|
+
<table>
|
172
|
+
<tr style="background:#ddd;">
|
173
|
+
<td>This</td>
|
174
|
+
<td>is</td>
|
175
|
+
<td>a</td>
|
176
|
+
<td>row</td>
|
177
|
+
</tr>
|
178
|
+
</table>
|
179
|
+
---
|
180
|
+
in: |-
|
181
|
+
|{background:#ddd}. Cell with gray background|
|
182
|
+
|\2. Cell spanning 2 columns|
|
183
|
+
|/3. Cell spanning 3 rows|
|
184
|
+
|>. Right-aligned cell|
|
185
|
+
out: |-
|
186
|
+
<table>
|
187
|
+
<tr>
|
188
|
+
<td style="background:#ddd;">Cell with gray background</td>
|
189
|
+
</tr>
|
190
|
+
<tr>
|
191
|
+
<td colspan="2">Cell spanning 2 columns</td>
|
192
|
+
</tr>
|
193
|
+
<tr>
|
194
|
+
<td rowspan="3">Cell spanning 3 rows</td>
|
195
|
+
</tr>
|
196
|
+
<tr>
|
197
|
+
<td style="text-align:right;">Right-aligned cell</td>
|
198
|
+
</tr>
|
199
|
+
</table>
|
200
|
+
# ---
|
201
|
+
# in: |-
|
202
|
+
# This is a "link":bob to Bob's website.
|
203
|
+
#
|
204
|
+
# [bob]http://itsbob.com/index.html
|
205
|
+
---
|
206
|
+
in: ACLU(American Civil Liberties Union)
|
207
|
+
out: <p><acronym title="American Civil Liberties Union">ACLU</acronym></p>
|
208
|
+
---
|
209
|
+
in: |-
|
210
|
+
h2{color:green}. This is a title
|
211
|
+
|
212
|
+
h3. This is a subhead
|
213
|
+
|
214
|
+
p{color:red}. This is some text of dubious character. Isn't the use of "quotes" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote.
|
215
|
+
|
216
|
+
bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised.
|
217
|
+
|
218
|
+
Simple list:
|
219
|
+
|
220
|
+
#{color:blue} one
|
221
|
+
# two
|
222
|
+
# three
|
223
|
+
|
224
|
+
Multi-level list:
|
225
|
+
|
226
|
+
# one
|
227
|
+
## aye
|
228
|
+
## bee
|
229
|
+
## see
|
230
|
+
# two
|
231
|
+
## x
|
232
|
+
## y
|
233
|
+
# three
|
234
|
+
|
235
|
+
Mixed list:
|
236
|
+
|
237
|
+
* Point one
|
238
|
+
* Point two
|
239
|
+
## Step 1
|
240
|
+
## Step 2
|
241
|
+
## Step 3
|
242
|
+
* Point three
|
243
|
+
** Sub point 1
|
244
|
+
** Sub point 2
|
245
|
+
|
246
|
+
|
247
|
+
Well, that went well. How about we insert an <a href="/" title="watch out">old-fashioned hypertext link</a>? Will the quote marks in the tags get messed up? No!
|
248
|
+
|
249
|
+
"This is a link (optional title)":http://www.textism.com
|
250
|
+
|
251
|
+
table{border:1px solid black}.
|
252
|
+
|_. this|_. is|_. a|_. header|
|
253
|
+
<{background:gray}. |\2. this is|{background:red;width:200px}. a|^<>{height:200px}. row|
|
254
|
+
|this|<>{padding:10px}. is|^. another|(bob#bob). row|
|
255
|
+
|
256
|
+
An image:
|
257
|
+
|
258
|
+
!/common/textist.gif(optional alt text)!
|
259
|
+
|
260
|
+
# Librarians rule
|
261
|
+
# Yes they do
|
262
|
+
# But you knew that
|
263
|
+
|
264
|
+
Some more text of dubious character. Here is a noisome string of CAPITAL letters. Here is something we want to _emphasize_.
|
265
|
+
That was a linebreak. And something to indicate *strength*. Of course I could use <em>my own HTML tags</em> if I <strong>felt</strong> like it.
|
266
|
+
|
267
|
+
h3. Coding
|
268
|
+
|
269
|
+
This <code>is some code, "isn't it"</code>. Watch those quote marks! Now for some preformatted text:
|
270
|
+
|
271
|
+
<pre>
|
272
|
+
<code>
|
273
|
+
$text = str_replace("<p>%::%</p>","",$text);
|
274
|
+
$text = str_replace("%::%</p>","",$text);
|
275
|
+
$text = str_replace("%::%","",$text);
|
276
|
+
|
277
|
+
</code>
|
278
|
+
</pre>
|
279
|
+
|
280
|
+
This isn't code.
|
281
|
+
|
282
|
+
|
283
|
+
So you see, my friends:
|
284
|
+
|
285
|
+
* The time is now
|
286
|
+
* The time is not later
|
287
|
+
* The time is not yesterday
|
288
|
+
* We must act
|
289
|
+
|
290
|
+
out: |-
|
291
|
+
<h2 style="color:green;">This is a title</h2>
|
292
|
+
|
293
|
+
<h3>This is a subhead</h3>
|
294
|
+
|
295
|
+
<p style="color:red;">This is some text of dubious character. Isn’t the use of “quotes” just lazy writing—and theft of ‘intellectual property’ besides? I think the time has come to see a block quote.</p>
|
296
|
+
|
297
|
+
<blockquote>
|
298
|
+
<p lang="fr">This is a block quote. I’ll admit it’s not the most exciting block quote ever devised.</p>
|
299
|
+
</blockquote>
|
300
|
+
|
301
|
+
<p>Simple list:</p>
|
302
|
+
<ol style="color:blue;">
|
303
|
+
<li>one</li>
|
304
|
+
<li>two</li>
|
305
|
+
<li>three</li>
|
306
|
+
</ol>
|
307
|
+
|
308
|
+
<p>Multi-level list:</p>
|
309
|
+
<ol>
|
310
|
+
<li>one
|
311
|
+
<ol>
|
312
|
+
<li>aye</li>
|
313
|
+
<li>bee</li>
|
314
|
+
<li>see</li>
|
315
|
+
</ol>
|
316
|
+
</li>
|
317
|
+
<li>two
|
318
|
+
<ol>
|
319
|
+
<li>x</li>
|
320
|
+
<li>y</li>
|
321
|
+
</ol>
|
322
|
+
</li>
|
323
|
+
<li>three</li>
|
324
|
+
</ol>
|
325
|
+
|
326
|
+
<p>Mixed list:</p>
|
327
|
+
<ul>
|
328
|
+
<li>Point one</li>
|
329
|
+
<li>Point two
|
330
|
+
<ol>
|
331
|
+
<li>Step 1</li>
|
332
|
+
<li>Step 2</li>
|
333
|
+
<li>Step 3</li>
|
334
|
+
</ol>
|
335
|
+
</li>
|
336
|
+
<li>Point three
|
337
|
+
<ul>
|
338
|
+
<li>Sub point 1</li>
|
339
|
+
<li>Sub point 2</li>
|
340
|
+
</ul></li>
|
341
|
+
</ul>
|
342
|
+
|
343
|
+
<p>Well, that went well. How about we insert an <a href="/" title="watch out">old-fashioned hypertext link</a>? Will the quote marks in the tags get messed up? No!</p>
|
344
|
+
|
345
|
+
<p><a href="http://www.textism.com" title="optional title">This is a link</a></p>
|
346
|
+
|
347
|
+
<table style="border:1px solid black;">
|
348
|
+
<tr>
|
349
|
+
<th>this</th>
|
350
|
+
<th>is</th>
|
351
|
+
<th>a</th>
|
352
|
+
<th>header</th>
|
353
|
+
</tr>
|
354
|
+
<tr style="background:gray;text-align:left;">
|
355
|
+
<td colspan="2">this is</td>
|
356
|
+
<td style="background:red;width:200px;">a</td>
|
357
|
+
<td style="vertical-align:top;height:200px;text-align:justify;">row</td>
|
358
|
+
</tr>
|
359
|
+
<tr>
|
360
|
+
<td>this</td>
|
361
|
+
<td style="padding:10px;text-align:justify;">is</td>
|
362
|
+
<td style="vertical-align:top;">another</td>
|
363
|
+
<td class="bob" id="bob">row</td>
|
364
|
+
</tr>
|
365
|
+
</table>
|
366
|
+
|
367
|
+
|
368
|
+
|
369
|
+
<p>An image:</p>
|
370
|
+
|
371
|
+
<p><img src="/common/textist.gif" title="optional alt text" alt="optional alt text" /></p>
|
372
|
+
<ol>
|
373
|
+
<li>Librarians rule</li>
|
374
|
+
<li>Yes they do</li>
|
375
|
+
<li>But you knew that</li>
|
376
|
+
</ol>
|
377
|
+
|
378
|
+
<p>Some more text of dubious character. Here is a noisome string of <span class="caps">CAPITAL</span> letters. Here is something we want to <em>emphasize</em>.
|
379
|
+
That was a linebreak. And something to indicate <strong>strength</strong>. Of course I could use <em>my own <span class="caps">HTML</span> tags</em> if I <strong>felt</strong> like it.</p>
|
380
|
+
|
381
|
+
<h3>Coding</h3>
|
382
|
+
|
383
|
+
<p>This <code>is some code, "isn't it"</code>. Watch those quote marks! Now for some preformatted text:</p>
|
384
|
+
|
385
|
+
|
386
|
+
<pre>
|
387
|
+
<code>
|
388
|
+
$text = str_replace("<p>%::%</p>","",$text);
|
389
|
+
$text = str_replace("%::%</p>","",$text);
|
390
|
+
$text = str_replace("%::%","",$text);
|
391
|
+
|
392
|
+
</code>
|
393
|
+
</pre>
|
394
|
+
<p>This isn’t code.</p>
|
395
|
+
|
396
|
+
<p>So you see, my friends:</p>
|
397
|
+
<ul>
|
398
|
+
<li>The time is now</li>
|
399
|
+
<li>The time is not later</li>
|
400
|
+
<li>The time is not yesterday</li>
|
401
|
+
<li>We must act</li>
|
402
|
+
</ul>
|
403
|
+
|
404
|
+
---
|
405
|
+
in: '"test":http://foo.com/b---ar'
|
406
|
+
out: <p><a href="http://foo.com/b---ar">test</a></p>
|
@@ -0,0 +1,720 @@
|
|
1
|
+
# $Id: mp3info.rb,v 1.5 2005/04/26 13:41:41 moumar Exp $
|
2
|
+
# = Description
|
3
|
+
#
|
4
|
+
# ruby-mp3info gives you access to low level informations on mp3 files
|
5
|
+
# (bitrate, length, samplerate, etc...). It can read, write, remove id3v1 tag
|
6
|
+
# and read id3v2. It is written in pure ruby.
|
7
|
+
#
|
8
|
+
#
|
9
|
+
# = Download
|
10
|
+
#
|
11
|
+
# get tar.gz at
|
12
|
+
# http://rubyforge.org/projects/ruby-mp3info/
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# = Installation
|
16
|
+
#
|
17
|
+
# $ ruby install.rb config
|
18
|
+
# $ ruby install.rb setup
|
19
|
+
# # ruby install.rb install
|
20
|
+
#
|
21
|
+
# or
|
22
|
+
#
|
23
|
+
# # gem install ruby-mp3info
|
24
|
+
#
|
25
|
+
#
|
26
|
+
# = Example
|
27
|
+
#
|
28
|
+
# require "mp3info"
|
29
|
+
#
|
30
|
+
# mp3info = Mp3Info.new("myfile.mp3")
|
31
|
+
# puts mp3info
|
32
|
+
#
|
33
|
+
#
|
34
|
+
# = Testing
|
35
|
+
#
|
36
|
+
# Test::Unit library is used for tests. see http://testunit.talbott.ws/
|
37
|
+
#
|
38
|
+
# $ ruby test.rb
|
39
|
+
#
|
40
|
+
#
|
41
|
+
# = ToDo
|
42
|
+
#
|
43
|
+
# * adding write support for ID3v2 tags
|
44
|
+
# * adding a test for id3v2
|
45
|
+
# * encoder detection
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# = Changelog
|
49
|
+
#
|
50
|
+
# [0.4 26/04/2005]
|
51
|
+
#
|
52
|
+
# * fixes in vbr mode
|
53
|
+
# * removed extract_info_from_head() function
|
54
|
+
# * now try several times to find a good header frame before giving up
|
55
|
+
# * correct handling of unicode in v2 tags. Require standard "iconv" library if such tags are used
|
56
|
+
# * FIXED if a tag appears more than one time, create an array with every value found for this tag
|
57
|
+
#
|
58
|
+
#
|
59
|
+
# [0.3 04/05/2004]
|
60
|
+
#
|
61
|
+
# * massive changes of most of the code to make it easier to read & hopefully run faster
|
62
|
+
# * ID2TAGS hash is just informative now, no use of it in the code. id3v2 tag fields are read in directly
|
63
|
+
# * added support for id3 v2.2 and v2.4 (0.2.1 only supported v2.3)
|
64
|
+
# * much improved vbr duration guessing
|
65
|
+
# * made Mp3Info#to_s output to be prettier
|
66
|
+
# * moved hastag1? and hastag2? to be class booleans instead of functions (now named hastag1 and hastag2)
|
67
|
+
# * fixed a bug on computing "error_protection" attribute
|
68
|
+
# * new attribute "tag", which is a sort of "universal" tag, regardless of the tag version, 1 or 2, with the same keys as @tag1
|
69
|
+
# * new method hastag?, which test the presence of any tag
|
70
|
+
#
|
71
|
+
#
|
72
|
+
# [0.2.1 04/09/2003]
|
73
|
+
#
|
74
|
+
# * filename attribute added
|
75
|
+
# * mp3 files are opened read-only now [Alan Davies <alan__DOT_davies__AT__thomson.com>]
|
76
|
+
# * Mp3Info#initialize: bugfixes [Alan Davies <alan__DOT_davies__AT__thomson.com>]
|
77
|
+
# * put NULLs in year field in id3v1 tags instead of zeros [Alan Davies <alan__DOT_davies__AT__thomson.com>]
|
78
|
+
# * Mp3Info#gettag1: remove null at end of strings [Alan Davies <alan__DOT_davies__AT__thomson.com>]
|
79
|
+
# * Mp3Info#extract_infos_from_head(): some brackets missed [Alan Davies <alan__DOT_davies__AT__thomson.com>]
|
80
|
+
#
|
81
|
+
#
|
82
|
+
# [0.2 18/08/2003]
|
83
|
+
#
|
84
|
+
# * writing, reading and removing of id3v1 tags
|
85
|
+
# * reading of id3v2 tags
|
86
|
+
# * test suite improved
|
87
|
+
# * to_s method added
|
88
|
+
# * length attribute is a Float now
|
89
|
+
#
|
90
|
+
#
|
91
|
+
# [0.1 17/03/2003]
|
92
|
+
#
|
93
|
+
# * Initial version
|
94
|
+
#
|
95
|
+
#
|
96
|
+
# License:: Ruby
|
97
|
+
# Author:: Guillaume Pierronnet (mailto:moumar_AT__rubyforge_DOT_org)
|
98
|
+
# Website:: http://ruby-mp3info.rubyforge.org/
|
99
|
+
|
100
|
+
# Raised on any kind of error related to ruby-mp3info
|
101
|
+
class Mp3InfoError < StandardError ; end
|
102
|
+
|
103
|
+
class Mp3InfoInternalError < StandardError #:nodoc:
|
104
|
+
end
|
105
|
+
|
106
|
+
class Numeric
|
107
|
+
### returns the selected bit range (b, a) as a number
|
108
|
+
### NOTE: b > a if not, returns 0
|
109
|
+
def bits(b, a)
|
110
|
+
t = 0
|
111
|
+
b.downto(a) { |i| t += t + self[i] }
|
112
|
+
t
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class Hash
|
117
|
+
### lets you specify hash["key"] as hash.key
|
118
|
+
### this came from CodingInRuby on RubyGarden
|
119
|
+
### http://www.rubygarden.org/ruby?CodingInRuby
|
120
|
+
def method_missing(meth,*args)
|
121
|
+
if /=$/=~(meth=meth.id2name) then
|
122
|
+
self[meth[0...-1]] = (args.length<2 ? args[0] : args)
|
123
|
+
else
|
124
|
+
self[meth]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class File
|
130
|
+
def get32bits
|
131
|
+
(getc << 24) + (getc << 16) + (getc << 8) + getc
|
132
|
+
end
|
133
|
+
def get_syncsafe
|
134
|
+
(getc << 21) + (getc << 14) + (getc << 7) + getc
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class Mp3Info
|
139
|
+
|
140
|
+
VERSION = "0.4"
|
141
|
+
|
142
|
+
LAYER = [ nil, 3, 2, 1]
|
143
|
+
BITRATE = [
|
144
|
+
[
|
145
|
+
[32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448],
|
146
|
+
[32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384],
|
147
|
+
[32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] ],
|
148
|
+
[
|
149
|
+
[32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256],
|
150
|
+
[8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160],
|
151
|
+
[8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160]
|
152
|
+
]
|
153
|
+
]
|
154
|
+
SAMPLERATE = [
|
155
|
+
[ 44100, 48000, 32000 ],
|
156
|
+
[ 22050, 24000, 16000 ]
|
157
|
+
]
|
158
|
+
CHANNEL_MODE = [ "Stereo", "JStereo", "Dual Channel", "Single Channel"]
|
159
|
+
|
160
|
+
GENRES = [
|
161
|
+
"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
|
162
|
+
"Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
|
163
|
+
"Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
|
164
|
+
"Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
|
165
|
+
"Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
|
166
|
+
"Fusion", "Trance", "Classical", "Instrumental", "Acid", "House",
|
167
|
+
"Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
|
168
|
+
"Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock",
|
169
|
+
"Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
|
170
|
+
"Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
|
171
|
+
"Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
|
172
|
+
"New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
|
173
|
+
"Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
|
174
|
+
"Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing",
|
175
|
+
"Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
|
176
|
+
"Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
|
177
|
+
"Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
|
178
|
+
"Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
|
179
|
+
"Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
|
180
|
+
"Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
|
181
|
+
"Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
|
182
|
+
"Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
|
183
|
+
"Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
|
184
|
+
"Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C",
|
185
|
+
"Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
|
186
|
+
"SynthPop" ]
|
187
|
+
|
188
|
+
|
189
|
+
ID2TAGS = {
|
190
|
+
"AENC" => "Audio encryption",
|
191
|
+
"APIC" => "Attached picture",
|
192
|
+
"COMM" => "Comments",
|
193
|
+
"COMR" => "Commercial frame",
|
194
|
+
"ENCR" => "Encryption method registration",
|
195
|
+
"EQUA" => "Equalization",
|
196
|
+
"ETCO" => "Event timing codes",
|
197
|
+
"GEOB" => "General encapsulated object",
|
198
|
+
"GRID" => "Group identification registration",
|
199
|
+
"IPLS" => "Involved people list",
|
200
|
+
"LINK" => "Linked information",
|
201
|
+
"MCDI" => "Music CD identifier",
|
202
|
+
"MLLT" => "MPEG location lookup table",
|
203
|
+
"OWNE" => "Ownership frame",
|
204
|
+
"PRIV" => "Private frame",
|
205
|
+
"PCNT" => "Play counter",
|
206
|
+
"POPM" => "Popularimeter",
|
207
|
+
"POSS" => "Position synchronisation frame",
|
208
|
+
"RBUF" => "Recommended buffer size",
|
209
|
+
"RVAD" => "Relative volume adjustment",
|
210
|
+
"RVRB" => "Reverb",
|
211
|
+
"SYLT" => "Synchronized lyric/text",
|
212
|
+
"SYTC" => "Synchronized tempo codes",
|
213
|
+
"TALB" => "Album/Movie/Show title",
|
214
|
+
"TBPM" => "BPM (beats per minute)",
|
215
|
+
"TCOM" => "Composer",
|
216
|
+
"TCON" => "Content type",
|
217
|
+
"TCOP" => "Copyright message",
|
218
|
+
"TDAT" => "Date",
|
219
|
+
"TDLY" => "Playlist delay",
|
220
|
+
"TENC" => "Encoded by",
|
221
|
+
"TEXT" => "Lyricist/Text writer",
|
222
|
+
"TFLT" => "File type",
|
223
|
+
"TIME" => "Time",
|
224
|
+
"TIT1" => "Content group description",
|
225
|
+
"TIT2" => "Title/songname/content description",
|
226
|
+
"TIT3" => "Subtitle/Description refinement",
|
227
|
+
"TKEY" => "Initial key",
|
228
|
+
"TLAN" => "Language(s)",
|
229
|
+
"TLEN" => "Length",
|
230
|
+
"TMED" => "Media type",
|
231
|
+
"TOAL" => "Original album/movie/show title",
|
232
|
+
"TOFN" => "Original filename",
|
233
|
+
"TOLY" => "Original lyricist(s)/text writer(s)",
|
234
|
+
"TOPE" => "Original artist(s)/performer(s)",
|
235
|
+
"TORY" => "Original release year",
|
236
|
+
"TOWN" => "File owner/licensee",
|
237
|
+
"TPE1" => "Lead performer(s)/Soloist(s)",
|
238
|
+
"TPE2" => "Band/orchestra/accompaniment",
|
239
|
+
"TPE3" => "Conductor/performer refinement",
|
240
|
+
"TPE4" => "Interpreted, remixed, or otherwise modified by",
|
241
|
+
"TPOS" => "Part of a set",
|
242
|
+
"TPUB" => "Publisher",
|
243
|
+
"TRCK" => "Track number/Position in set",
|
244
|
+
"TRDA" => "Recording dates",
|
245
|
+
"TRSN" => "Internet radio station name",
|
246
|
+
"TRSO" => "Internet radio station owner",
|
247
|
+
"TSIZ" => "Size",
|
248
|
+
"TSRC" => "ISRC (international standard recording code)",
|
249
|
+
"TSSE" => "Software/Hardware and settings used for encoding",
|
250
|
+
"TYER" => "Year",
|
251
|
+
"TXXX" => "User defined text information frame",
|
252
|
+
"UFID" => "Unique file identifier",
|
253
|
+
"USER" => "Terms of use",
|
254
|
+
"USLT" => "Unsychronized lyric/text transcription",
|
255
|
+
"WCOM" => "Commercial information",
|
256
|
+
"WCOP" => "Copyright/Legal information",
|
257
|
+
"WOAF" => "Official audio file webpage",
|
258
|
+
"WOAR" => "Official artist/performer webpage",
|
259
|
+
"WOAS" => "Official audio source webpage",
|
260
|
+
"WORS" => "Official internet radio station homepage",
|
261
|
+
"WPAY" => "Payment",
|
262
|
+
"WPUB" => "Publishers official webpage",
|
263
|
+
"WXXX" => "User defined URL link frame"
|
264
|
+
}
|
265
|
+
|
266
|
+
TAGSIZE = 128
|
267
|
+
#MAX_FRAME_COUNT = 6 #number of frame to read for encoder detection
|
268
|
+
|
269
|
+
# mpeg version = 1 or 2
|
270
|
+
attr_reader(:mpeg_version)
|
271
|
+
|
272
|
+
# layer = 1, 2, or 3
|
273
|
+
attr_reader(:layer)
|
274
|
+
|
275
|
+
# bitrate in kbps
|
276
|
+
attr_reader(:bitrate)
|
277
|
+
|
278
|
+
# samplerate in Hz
|
279
|
+
attr_reader(:samplerate)
|
280
|
+
|
281
|
+
# channel mode => "Stereo", "JStereo", "Dual Channel" or "Single Channel"
|
282
|
+
attr_reader(:channel_mode)
|
283
|
+
|
284
|
+
# variable bitrate => true or false
|
285
|
+
attr_reader(:vbr)
|
286
|
+
|
287
|
+
# length in seconds as a Float
|
288
|
+
attr_reader(:length)
|
289
|
+
|
290
|
+
# error protection => true or false
|
291
|
+
attr_reader(:error_protection)
|
292
|
+
|
293
|
+
#a sort of "universal" tag, regardless of the tag version, 1 or 2, with the same keys as @tag1
|
294
|
+
attr_reader(:tag)
|
295
|
+
|
296
|
+
# id3v1 tag has a Hash. You can modify it, it will be written when calling
|
297
|
+
# "close" method.
|
298
|
+
attr_accessor(:tag1)
|
299
|
+
|
300
|
+
# id3v2 tag as a Hash
|
301
|
+
attr_reader(:tag2)
|
302
|
+
|
303
|
+
# the original filename
|
304
|
+
attr_reader(:filename)
|
305
|
+
|
306
|
+
# Moved hastag1? and hastag2? to be booleans
|
307
|
+
attr_reader(:hastag1, :hastag2)
|
308
|
+
|
309
|
+
# Test the presence of an id3v1 tag in file +filename+
|
310
|
+
def self.hastag1?(filename)
|
311
|
+
File.open(filename) { |f|
|
312
|
+
f.seek(-TAGSIZE, File::SEEK_END)
|
313
|
+
f.read(3) == "TAG"
|
314
|
+
}
|
315
|
+
end
|
316
|
+
|
317
|
+
# Test the presence of an id3v2 tag in file +filename+
|
318
|
+
def self.hastag2?(filename)
|
319
|
+
File.open(filename) { |f|
|
320
|
+
f.read(3) == "ID3"
|
321
|
+
}
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
# Remove id3v1 tag from +filename+
|
326
|
+
def self.removetag1(filename)
|
327
|
+
if self.hastag1?(filename)
|
328
|
+
newsize = File.size(filename) - TAGSIZE
|
329
|
+
File.open(filename, "r+") { |f| f.truncate(newsize) }
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# Instantiate a new Mp3Info object with name +filename+
|
334
|
+
def initialize(filename)
|
335
|
+
$stderr.puts("#{self.class}::new() does not take block; use #{self.class}::open() instead") if block_given?
|
336
|
+
raise(Mp3InfoError, "empty file") unless File.stat(filename).size? #FIXME
|
337
|
+
@filename = filename
|
338
|
+
@hastag1, @hastag2 = false
|
339
|
+
@tag = Hash.new
|
340
|
+
@tag1 = Hash.new
|
341
|
+
@tag2 = Hash.new
|
342
|
+
|
343
|
+
@file = File.new(filename, "rb")
|
344
|
+
parse_tags
|
345
|
+
@tag_orig = @tag1.dup
|
346
|
+
|
347
|
+
#creation of a sort of "universal" tag, regardless of the tag version
|
348
|
+
if hastag2?
|
349
|
+
h = {
|
350
|
+
"title" => "TIT2",
|
351
|
+
"artist" => "TPE1",
|
352
|
+
"album" => "TALB",
|
353
|
+
"year" => "TYER",
|
354
|
+
"tracknum" => "TRCK",
|
355
|
+
"comments" => "COMM",
|
356
|
+
"genre" => 255,
|
357
|
+
"genre_s" => "TCON"
|
358
|
+
}
|
359
|
+
|
360
|
+
h.each { |k, v| @tag[k] = @tag2[v] }
|
361
|
+
|
362
|
+
elsif hastag1?
|
363
|
+
@tag = @tag1.dup
|
364
|
+
end
|
365
|
+
|
366
|
+
|
367
|
+
### extracts MPEG info from MPEG header and stores it in the hash @mpeg
|
368
|
+
### head (fixnum) = valid 4 byte MPEG header
|
369
|
+
|
370
|
+
found = false
|
371
|
+
|
372
|
+
5.times do
|
373
|
+
head = find_next_frame()
|
374
|
+
@mpeg_version = [2, 1][head[19]]
|
375
|
+
@layer = LAYER[head.bits(18,17)]
|
376
|
+
next if @layer.nil?
|
377
|
+
@bitrate = BITRATE[@mpeg_version-1][@layer-1][head.bits(15,12)-1]
|
378
|
+
@error_protection = head[16] == 0 ? true : false
|
379
|
+
@samplerate = SAMPLERATE[@mpeg_version-1][head.bits(11,10)]
|
380
|
+
@padding = (head[9] == 1 ? true : false)
|
381
|
+
@channel_mode = CHANNEL_MODE[@channel_num = head.bits(7,6)]
|
382
|
+
@copyright = (head[3] == 1 ? true : false)
|
383
|
+
@original = (head[2] == 1 ? true : false)
|
384
|
+
@vbr = false
|
385
|
+
found = true
|
386
|
+
break
|
387
|
+
end
|
388
|
+
|
389
|
+
raise(Mp3InfoError, "Cannot find good frame") unless found
|
390
|
+
|
391
|
+
|
392
|
+
seek = @mpeg_version == 1 ?
|
393
|
+
(@channel_num == 3 ? 17 : 32) :
|
394
|
+
(@channel_num == 3 ? 9 : 17)
|
395
|
+
|
396
|
+
@file.seek(seek, IO::SEEK_CUR)
|
397
|
+
|
398
|
+
vbr_head = @file.read(4)
|
399
|
+
if vbr_head == "Xing"
|
400
|
+
flags = @file.get32bits
|
401
|
+
@streamsize = @frames = 0
|
402
|
+
flags[1] == 1 and @frames = @file.get32bits
|
403
|
+
flags[2] == 1 and @streamsize = @file.get32bits
|
404
|
+
# currently this just skips the TOC entries if they're found
|
405
|
+
@file.seek(100, IO::SEEK_CUR) if flags[0] == 1
|
406
|
+
@vbr_quality = @file.get32bits if flags[3] == 1
|
407
|
+
@length = (26/1000.0)*@frames
|
408
|
+
@bitrate = (((@streamsize/@frames)*@samplerate)/144) >> 10
|
409
|
+
@vbr = true
|
410
|
+
else
|
411
|
+
# for cbr, calculate duration with the given bitrate
|
412
|
+
@streamsize = @file.stat.size - (@hastag1 ? TAGSIZE : 0) - (@hastag2 ? @tag2["length"] : 0)
|
413
|
+
@length = ((@streamsize << 3)/1000.0)/@bitrate
|
414
|
+
if @tag2["TLEN"]
|
415
|
+
# but if another duration is given and it isn't close (within 5%)
|
416
|
+
# assume the mp3 is vbr and go with the given duration
|
417
|
+
tlen = (@tag2["TLEN"].to_i)/1000
|
418
|
+
percent_diff = ((@length.to_i-tlen)/tlen.to_f)
|
419
|
+
if percent_diff.abs > 0.05
|
420
|
+
# without the xing header, this is the best guess without reading
|
421
|
+
# every single frame
|
422
|
+
@vbr = true
|
423
|
+
@length = @tag2["TLEN"].to_i/1000
|
424
|
+
@bitrate = (@streamsize / @bitrate) >> 10
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
# "block version" of Mp3Info::new()
|
431
|
+
def self.open(filename)
|
432
|
+
m = self.new(filename)
|
433
|
+
ret = nil
|
434
|
+
if block_given?
|
435
|
+
begin
|
436
|
+
ret = yield(m)
|
437
|
+
ensure
|
438
|
+
m.close
|
439
|
+
end
|
440
|
+
else
|
441
|
+
ret = m
|
442
|
+
end
|
443
|
+
ret
|
444
|
+
end
|
445
|
+
|
446
|
+
# Remove id3v1 from mp3
|
447
|
+
def removetag1
|
448
|
+
if hastag1?
|
449
|
+
newsize = @file.stat.size(filename) - TAGSIZE
|
450
|
+
@file.truncate(newsize)
|
451
|
+
@tag1.clear
|
452
|
+
end
|
453
|
+
self
|
454
|
+
end
|
455
|
+
|
456
|
+
# Has file an id3v1 or v2 tag? true or false
|
457
|
+
def hastag?
|
458
|
+
@hastag1 or @hastag2
|
459
|
+
end
|
460
|
+
|
461
|
+
# Has file an id3v1 tag? true or false
|
462
|
+
def hastag1?
|
463
|
+
@hastag1
|
464
|
+
end
|
465
|
+
|
466
|
+
# Has file an id3v2 tag? true or false
|
467
|
+
def hastag2?
|
468
|
+
@hastag2
|
469
|
+
end
|
470
|
+
|
471
|
+
|
472
|
+
# Flush pending modifications to tags and close the file
|
473
|
+
def close
|
474
|
+
return if @file.nil?
|
475
|
+
if @tag1 != @tag_orig
|
476
|
+
@tag_orig.update(@tag1)
|
477
|
+
#puts "@tag_orig: #{@tag_orig.inspect}"
|
478
|
+
@file.reopen(@filename, 'rb+')
|
479
|
+
@file.seek(-TAGSIZE, File::SEEK_END)
|
480
|
+
t = @file.read(3)
|
481
|
+
if t != 'TAG'
|
482
|
+
#append new tag
|
483
|
+
@file.seek(0, File::SEEK_END)
|
484
|
+
@file.write('TAG')
|
485
|
+
end
|
486
|
+
str = [
|
487
|
+
@tag_orig["title"]||"",
|
488
|
+
@tag_orig["artist"]||"",
|
489
|
+
@tag_orig["album"]||"",
|
490
|
+
((@tag_orig["year"] != 0) ? ("%04d" % @tag_orig["year"]) : "\0\0\0\0"),
|
491
|
+
@tag_orig["comments"]||"",
|
492
|
+
0,
|
493
|
+
@tag_orig["tracknum"]||0,
|
494
|
+
@tag_orig["genre"]||255
|
495
|
+
].pack("Z30Z30Z30Z4Z28CCC")
|
496
|
+
@file.write(str)
|
497
|
+
end
|
498
|
+
@file.close
|
499
|
+
@file = nil
|
500
|
+
end
|
501
|
+
|
502
|
+
# inspect inside Mp3Info
|
503
|
+
def to_s
|
504
|
+
s = "MPEG #{@mpeg_version} Layer #{@layer} #{@vbr ? "VBR" : "CBR"} #{@bitrate} Kbps #{@channel_mode} #{@samplerate} Hz length #{@length} sec. error protection #{@error_protection} "
|
505
|
+
s << "tag1: "+@tag1.inspect+"\n" if @hastag1
|
506
|
+
s << "tag2: "+@tag2.inspect+"\n" if @hastag2
|
507
|
+
s
|
508
|
+
end
|
509
|
+
|
510
|
+
|
511
|
+
private
|
512
|
+
|
513
|
+
### parses the id3 tags of the currently open @file
|
514
|
+
def parse_tags
|
515
|
+
return if @file.stat.size < TAGSIZE # file is too small
|
516
|
+
@file.seek(0)
|
517
|
+
f3 = @file.read(3)
|
518
|
+
gettag1 if f3 == "TAG" # v1 tag at beginning
|
519
|
+
gettag2 if f3 == "ID3" # v2 tag at beginning
|
520
|
+
unless @hastag1 # v1 tag at end
|
521
|
+
# this preserves the file pos if tag2 found, since gettag2 leaves
|
522
|
+
# the file at the best guess as to the first MPEG frame
|
523
|
+
pos = (@hastag2 ? @file.pos : 0)
|
524
|
+
# seek to where id3v1 tag should be
|
525
|
+
@file.seek(-TAGSIZE, IO::SEEK_END)
|
526
|
+
gettag1 if @file.read(3) == "TAG"
|
527
|
+
@file.seek(pos)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
### reads in id3 field strings, stripping out non-printable chars
|
532
|
+
### len (fixnum) = number of chars in field
|
533
|
+
### returns string
|
534
|
+
def read_id3_string(len)
|
535
|
+
#FIXME handle unicode strings
|
536
|
+
#return @file.read(len)
|
537
|
+
s = ""
|
538
|
+
len.times do
|
539
|
+
c = @file.getc
|
540
|
+
# only append printable characters
|
541
|
+
s << c if c >= 32 and c < 254
|
542
|
+
end
|
543
|
+
return s.strip
|
544
|
+
#return (s[0..2] == "eng" ? s[3..-1] : s)
|
545
|
+
end
|
546
|
+
|
547
|
+
### gets id3v1 tag information from @file
|
548
|
+
### assumes @file is pointing to char after "TAG" id
|
549
|
+
def gettag1
|
550
|
+
@hastag1 = true
|
551
|
+
@tag1["title"] = read_id3_string(30)
|
552
|
+
@tag1["artist"] = read_id3_string(30)
|
553
|
+
@tag1["album"] = read_id3_string(30)
|
554
|
+
year_t = read_id3_string(4).to_i
|
555
|
+
@tag1["year"] = year_t unless year_t == 0
|
556
|
+
comments = @file.read(30)
|
557
|
+
if comments[-2] == 0
|
558
|
+
@tag1["tracknum"] = comments[-1].to_i
|
559
|
+
comments.chop! #remove the last char
|
560
|
+
end
|
561
|
+
#@tag1["comments"] = comments.sub!(/\0.*$/, '')
|
562
|
+
@tag1["comments"] = comments.strip
|
563
|
+
@tag1["genre"] = @file.getc
|
564
|
+
@tag1["genre_s"] = GENRES[@tag1["genre"]] || ""
|
565
|
+
end
|
566
|
+
|
567
|
+
### gets id3v2 tag information from @file
|
568
|
+
def gettag2
|
569
|
+
@file.seek(3)
|
570
|
+
version_maj, version_min, flags = @file.read(3).unpack("CCB4")
|
571
|
+
unsync, ext_header, experimental, footer = (0..3).collect { |i| flags[i].chr == '1' }
|
572
|
+
return unless [2, 3, 4].include?(version_maj)
|
573
|
+
@hastag2 = true
|
574
|
+
@tag2["version"] = "2.#{version_maj}.#{version_min}"
|
575
|
+
tag2_len = @file.get_syncsafe
|
576
|
+
case version_maj
|
577
|
+
when 2
|
578
|
+
read_id3v2_2_frames(tag2_len)
|
579
|
+
when 3,4
|
580
|
+
# seek past extended header if present
|
581
|
+
@file.seek(@file.get_syncsafe - 4, IO::SEEK_CUR) if ext_header
|
582
|
+
read_id3v2_3_frames(tag2_len)
|
583
|
+
end
|
584
|
+
tag2["length"] = @file.pos
|
585
|
+
# we should now have @file sitting at the first MPEG frame
|
586
|
+
end
|
587
|
+
|
588
|
+
### runs thru @file one char at a time looking for best guess of first MPEG
|
589
|
+
### frame, which should be first 0xff byte after id3v2 padding zero's
|
590
|
+
### returns true
|
591
|
+
def v2_end?
|
592
|
+
until @file.getc == 0xff
|
593
|
+
end
|
594
|
+
@file.seek(-1, IO::SEEK_CUR)
|
595
|
+
true
|
596
|
+
end
|
597
|
+
|
598
|
+
### reads id3 ver 2.3.x/2.4.x frames and adds the contents to @tag2 hash
|
599
|
+
### tag2_len (fixnum) = length of entire id3v2 data, as reported in header
|
600
|
+
### NOTE: the id3v2 header does not take padding zero's into consideration
|
601
|
+
def read_id3v2_3_frames(tag2_len)
|
602
|
+
v2end_found = false
|
603
|
+
until v2end_found # there are 2 ways to end the loop
|
604
|
+
name = @file.read(4)
|
605
|
+
if name[0] == 0
|
606
|
+
@file.seek(-4, IO::SEEK_CUR) # 1. find a padding zero,
|
607
|
+
v2end_found = v2_end? # so we seek to end of zeros
|
608
|
+
else
|
609
|
+
size = @file.get32bits
|
610
|
+
@file.seek(2, IO::SEEK_CUR) # skip flags
|
611
|
+
add_value_to_tag2(name, size)
|
612
|
+
# case name
|
613
|
+
# when /T[A-Z]+|COMM/
|
614
|
+
# data = read_id3_string(size-1)
|
615
|
+
# add_value_to_tag2(name, data)
|
616
|
+
# else
|
617
|
+
# @file.seek(size-1, IO::SEEK_CUR)
|
618
|
+
# end
|
619
|
+
v2end_found = true if @file.pos >= tag2_len # 2. reach length from header
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
### reads id3 ver 2.2.x frames and adds the contents to @tag2 hash
|
625
|
+
### tag2_len (fixnum) = length of entire id3v2 data, as reported in header
|
626
|
+
### NOTE: the id3v2 header does not take padding zero's into consideration
|
627
|
+
def read_id3v2_2_frames(tag2_len)
|
628
|
+
v2end_found = false
|
629
|
+
until v2end_found
|
630
|
+
name = @file.read(3)
|
631
|
+
if name[0] == 0
|
632
|
+
@file.seek(-3, IO::SEEK_CUR)
|
633
|
+
v2end_found = v2_end?
|
634
|
+
else
|
635
|
+
size = (@file.getc << 16) + (@file.getc << 8) + @file.getc
|
636
|
+
add_value_to_tag2(name, size)
|
637
|
+
v2end_found = true if @file.pos >= tag2_len
|
638
|
+
end
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
### Add data to tag2["name"]
|
643
|
+
### read lang_encoding, decode data if unicode and
|
644
|
+
### create an array if the key ever exists in the tag
|
645
|
+
def add_value_to_tag2(name, size)
|
646
|
+
lang_encoding = @file.getc # language encoding bit 0 for iso_8859_1, 1 for unicode
|
647
|
+
data = size == 0 ? "" : @file.read(size-1)
|
648
|
+
|
649
|
+
if lang_encoding == 1 and name[0] == ?T
|
650
|
+
require "iconv"
|
651
|
+
|
652
|
+
#strip byte-order bytes at the beginning of the unicode string if they exists
|
653
|
+
data[0..3] =~ /^[\xff\xfe]+$/ and data = data[2..-1]
|
654
|
+
|
655
|
+
data = Iconv.iconv("ISO-8859-1", "UNICODE", data)[0]
|
656
|
+
end
|
657
|
+
|
658
|
+
if @tag2.keys.include?(name)
|
659
|
+
unless @tag2[name].is_a?(Array)
|
660
|
+
keep = @tag2[name]
|
661
|
+
@tag2[name] = []
|
662
|
+
@tag2[name] << keep
|
663
|
+
end
|
664
|
+
@tag2[name] << data
|
665
|
+
else
|
666
|
+
@tag2[name] = data
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
### reads through @file from current pos until it finds a valid MPEG header
|
671
|
+
### returns the MPEG header as FixNum
|
672
|
+
def find_next_frame
|
673
|
+
# @file will now be sitting at the best guess for where the MPEG frame is.
|
674
|
+
# It should be at byte 0 when there's no id3v2 tag.
|
675
|
+
# It should be at the end of the id3v2 tag or the zero padding if there
|
676
|
+
# is a id3v2 tag.
|
677
|
+
start_pos = @file.pos
|
678
|
+
dummyproof = @file.stat.size - @file.pos
|
679
|
+
dummyproof.times do |i|
|
680
|
+
if @file.getc == 0xff
|
681
|
+
head = 0xff000000 + (@file.getc << 16) + (@file.getc << 8) + @file.getc
|
682
|
+
if check_head(head)
|
683
|
+
return head
|
684
|
+
else
|
685
|
+
@file.seek(-3, IO::SEEK_CUR)
|
686
|
+
end
|
687
|
+
end
|
688
|
+
end
|
689
|
+
raise Mp3InfoError
|
690
|
+
end
|
691
|
+
|
692
|
+
### checks the given header to see if it is valid
|
693
|
+
### head (fixnum) = 4 byte value to test for MPEG header validity
|
694
|
+
### returns true if valid, false if not
|
695
|
+
def check_head(head)
|
696
|
+
return false if head & 0xffe00000 != 0xffe00000 # 11 bit MPEG frame sync
|
697
|
+
return false if head & 0x00060000 == 0x00060000 # 2 bit layer type
|
698
|
+
return false if head & 0x0000f000 == 0x0000f000 # 4 bit bitrate
|
699
|
+
return false if head & 0x0000f000 == 0x00000000 # free format bitstream
|
700
|
+
return false if head & 0x00000c00 == 0x00000c00 # 2 bit frequency
|
701
|
+
return false if head & 0xffff0000 == 0xfffe0000
|
702
|
+
true
|
703
|
+
end
|
704
|
+
|
705
|
+
end
|
706
|
+
|
707
|
+
if $0 == __FILE__
|
708
|
+
while filename = ARGV.shift
|
709
|
+
begin
|
710
|
+
info = Mp3Info.new(filename)
|
711
|
+
puts filename
|
712
|
+
#puts "MPEG #{info.mpeg_version} Layer #{info.layer} #{info.vbr ? "VBR" : "CBR"} #{info.bitrate} Kbps \
|
713
|
+
#{info.channel_mode} #{info.samplerate} Hz length #{info.length} sec."
|
714
|
+
puts info
|
715
|
+
rescue Mp3InfoError => e
|
716
|
+
puts "#{filename}\nERROR: #{e}"
|
717
|
+
end
|
718
|
+
puts
|
719
|
+
end
|
720
|
+
end
|