deployer пре 3 година
родитељ
комит
0efe962397
100 измењених фајлова са 5307 додато и 0 уклоњено
  1. 16 0
      Dockerfile
  2. 2 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/.gitignore
  3. 21 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/LICENSE
  4. 47 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/README.md
  5. 17 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output1.txt
  6. 14 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output2.txt
  7. 15 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output3.txt
  8. 14 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output4.txt
  9. 14 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output5.txt
  10. 15 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output6.txt
  11. 14 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output7.txt
  12. 1199 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/stoplist/中文停用词表(1208个).txt
  13. 116 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/stoplist/中文分隔词词库.txt
  14. 0 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/Abstract.txt
  15. 1 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/Satellite.txt
  16. 1 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/ZTE.txt
  17. 1 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本1.txt
  18. 219 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本2.txt
  19. 26 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本3.txt
  20. 67 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本4.txt
  21. 21 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本5.txt
  22. 123 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本6.txt
  23. 45 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本7.txt
  24. 10 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/example.py
  25. 127 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/Rake.py
  26. 0 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/__init__.py
  27. 29 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/utils.py
  28. 23 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/word.py
  29. 2 0
      Rake_For_Chinese-master/Rake_For_Chinese-master/requirements.txt
  30. BIN
      __pycache__/main.cpython-38.pyc
  31. BIN
      __pycache__/util.cpython-38.pyc
  32. 405 0
      autoSub_dev/autosub/__init__-0.4.0.py
  33. 434 0
      autoSub_dev/autosub/__init__.py
  34. BIN
      autoSub_dev/autosub/__pycache__/__init__.cpython-37.pyc
  35. BIN
      autoSub_dev/autosub/__pycache__/__init__.cpython-38.pyc
  36. BIN
      autoSub_dev/autosub/__pycache__/__init__.cpython-39.pyc
  37. BIN
      autoSub_dev/autosub/__pycache__/constants.cpython-37.pyc
  38. BIN
      autoSub_dev/autosub/__pycache__/constants.cpython-38.pyc
  39. BIN
      autoSub_dev/autosub/__pycache__/constants.cpython-39.pyc
  40. BIN
      autoSub_dev/autosub/__pycache__/formatters.cpython-37.pyc
  41. BIN
      autoSub_dev/autosub/__pycache__/formatters.cpython-38.pyc
  42. BIN
      autoSub_dev/autosub/__pycache__/formatters.cpython-39.pyc
  43. 118 0
      autoSub_dev/autosub/constants.py
  44. 66 0
      autoSub_dev/autosub/formatters.py
  45. BIN
      autoSub_dev/pytranscriber/.DS_Store
  46. 0 0
      autoSub_dev/pytranscriber/control/__init__.py
  47. BIN
      autoSub_dev/pytranscriber/control/__pycache__/__init__.cpython-37.pyc
  48. BIN
      autoSub_dev/pytranscriber/control/__pycache__/__init__.cpython-38.pyc
  49. BIN
      autoSub_dev/pytranscriber/control/__pycache__/__init__.cpython-39.pyc
  50. BIN
      autoSub_dev/pytranscriber/control/__pycache__/ctr_autosub.cpython-37.pyc
  51. BIN
      autoSub_dev/pytranscriber/control/__pycache__/ctr_autosub.cpython-38.pyc
  52. BIN
      autoSub_dev/pytranscriber/control/__pycache__/ctr_autosub.cpython-39.pyc
  53. BIN
      autoSub_dev/pytranscriber/control/__pycache__/ctr_main.cpython-37.pyc
  54. BIN
      autoSub_dev/pytranscriber/control/__pycache__/ctr_main.cpython-38.pyc
  55. BIN
      autoSub_dev/pytranscriber/control/__pycache__/ctr_main.cpython-39.pyc
  56. BIN
      autoSub_dev/pytranscriber/control/__pycache__/thread_cancel_autosub.cpython-37.pyc
  57. BIN
      autoSub_dev/pytranscriber/control/__pycache__/thread_cancel_autosub.cpython-38.pyc
  58. BIN
      autoSub_dev/pytranscriber/control/__pycache__/thread_cancel_autosub.cpython-39.pyc
  59. BIN
      autoSub_dev/pytranscriber/control/__pycache__/thread_exec_autosub.cpython-37.pyc
  60. BIN
      autoSub_dev/pytranscriber/control/__pycache__/thread_exec_autosub.cpython-38.pyc
  61. BIN
      autoSub_dev/pytranscriber/control/__pycache__/thread_exec_autosub.cpython-39.pyc
  62. 145 0
      autoSub_dev/pytranscriber/control/ctr_autosub.py
  63. 413 0
      autoSub_dev/pytranscriber/control/ctr_main.py
  64. 14 0
      autoSub_dev/pytranscriber/control/thread_cancel_autosub.py
  65. 120 0
      autoSub_dev/pytranscriber/control/thread_exec_autosub.py
  66. 0 0
      autoSub_dev/pytranscriber/gui/__init__.py
  67. BIN
      autoSub_dev/pytranscriber/gui/__pycache__/__init__.cpython-37.pyc
  68. BIN
      autoSub_dev/pytranscriber/gui/__pycache__/__init__.cpython-38.pyc
  69. BIN
      autoSub_dev/pytranscriber/gui/__pycache__/__init__.cpython-39.pyc
  70. BIN
      autoSub_dev/pytranscriber/gui/__pycache__/gui.cpython-37.pyc
  71. BIN
      autoSub_dev/pytranscriber/gui/__pycache__/gui.cpython-38.pyc
  72. BIN
      autoSub_dev/pytranscriber/gui/__pycache__/gui.cpython-39.pyc
  73. 120 0
      autoSub_dev/pytranscriber/gui/gui.py
  74. 266 0
      autoSub_dev/pytranscriber/gui/gui.ui
  75. 0 0
      autoSub_dev/pytranscriber/model/__init__.py
  76. BIN
      autoSub_dev/pytranscriber/model/__pycache__/__init__.cpython-37.pyc
  77. BIN
      autoSub_dev/pytranscriber/model/__pycache__/__init__.cpython-38.pyc
  78. BIN
      autoSub_dev/pytranscriber/model/__pycache__/__init__.cpython-39.pyc
  79. BIN
      autoSub_dev/pytranscriber/model/__pycache__/param_autosub.cpython-37.pyc
  80. BIN
      autoSub_dev/pytranscriber/model/__pycache__/param_autosub.cpython-38.pyc
  81. BIN
      autoSub_dev/pytranscriber/model/__pycache__/param_autosub.cpython-39.pyc
  82. 22 0
      autoSub_dev/pytranscriber/model/param_autosub.py
  83. 0 0
      autoSub_dev/pytranscriber/util/__init__.py
  84. BIN
      autoSub_dev/pytranscriber/util/__pycache__/__init__.cpython-37.pyc
  85. BIN
      autoSub_dev/pytranscriber/util/__pycache__/__init__.cpython-38.pyc
  86. BIN
      autoSub_dev/pytranscriber/util/__pycache__/__init__.cpython-39.pyc
  87. BIN
      autoSub_dev/pytranscriber/util/__pycache__/srtparser.cpython-37.pyc
  88. BIN
      autoSub_dev/pytranscriber/util/__pycache__/srtparser.cpython-38.pyc
  89. BIN
      autoSub_dev/pytranscriber/util/__pycache__/srtparser.cpython-39.pyc
  90. BIN
      autoSub_dev/pytranscriber/util/__pycache__/util.cpython-37.pyc
  91. BIN
      autoSub_dev/pytranscriber/util/__pycache__/util.cpython-38.pyc
  92. BIN
      autoSub_dev/pytranscriber/util/__pycache__/util.cpython-39.pyc
  93. 49 0
      autoSub_dev/pytranscriber/util/srtparser.py
  94. 44 0
      autoSub_dev/pytranscriber/util/util.py
  95. 14 0
      autoSub_dev/run.py
  96. 39 0
      autoSub_dev/script.txt
  97. BIN
      autoSub_dev/src.mp4
  98. 405 0
      autosub/__init__-0.4.0.py
  99. 434 0
      autosub/__init__.py
  100. BIN
      autosub/__pycache__/__init__.cpython-37.pyc

+ 16 - 0
Dockerfile

@@ -0,0 +1,16 @@
+FROM ubuntu:20.04
+
+RUN apt update
+RUN apt install -y software-properties-common
+RUN add-apt-repository -y ppa:openshot.developers/ppa
+RUN apt update
+RUN DEBIAN_FRONTEND=noninteractive apt-get install keyboard-configuration -y
+RUN apt-get update && apt-get install -y apt-transport-https
+RUN apt-get install python3-pip -y
+RUN apt-get install vim -y
+
+RUN apt-get install python3-openshot -y
+RUN apt-get install openshot-qt -y
+RUN apt install -y xvfb
+RUN pip3 install ffmpy
+

+ 2 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/.gitignore

@@ -0,0 +1,2 @@
+# Discard Local Test Cases
+__pycache__

+ 21 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Xu Ruoyang
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 47 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/README.md

@@ -0,0 +1,47 @@
+# Rake 算法的中文应用
+这是一个对 Rose, S., Engel, D., Cramer, N., & Cowley, W. (2010). Automatic Keyword Extraction from Individual Documents. In M. W. Berry & J. Kogan (Eds.), Text Mining: Theory and Applications: John Wiley & Sons. 中提及的 Rapid Automatic Keyword Extraction 在中文上的应用, MIT License
+
+# 安装说明
+代码写于 Python 版本 3.6.5; 此应用使用了中文分词工具结巴 https://github.com/fxsjy/jieba 可用 `pip install jieba` 安装结巴。
+
+# 主要功能
+使用 RAKE 算法从中文段落中选取关键词
+
+# Rake_For_Chinese
+A Python implementation of the Rapid Automatic Keyword Extraction (RAKE) algorithm as described in: Rose, S., Engel, D., Cramer, N., & Cowley, W. (2010). Automatic Keyword Extraction from Individual Documents. In M. W. Berry & J. Kogan (Eds.), Text Mining: Theory and Applications: John Wiley & Sons.
+Codebase in MIT License
+
+# Requirement
+This package requires the Chinese text segmentation package Jieba. Run install through `requirements.txt`
+
+## Functional Overview
+RAKE Keyword Extraction is an algorithm that is by design corpus-independent and language-independent. In a nutshell, it calculates scores for words based on its independent occurrence and its occurrence in phrases, and then combine all scores for every word inside a phrase to get the score for the phrase, with some additional criterias to eliminate boundary conditions.
+
+This method however, cannot be directly applied to Chinese since first, there are no obvious word deliminators and second when we come to parsing phrases, there's more variety to it than that in English and other language with similar syntaxes.
+
+Generation of "Word" and "Phrases" as needed by RAKE algorithm sought help from another Chinese Text Segmentation package, Jieba. Jieba is used to cut raw texts into segments of word. Then the list is filter with PoS property, stopword and conjunction word list and punctuation list to parse phrases. 
+
+## Example Code
+See `example.py`
+
+## Sample Output
+Take news article at this link for example: http://www.pingwest.com/sony-expo-2018-at-chengdu/
+
+Sample output in the following, with the output of this implementation in the **last line**
+
+```
+TextRank4ZH-关键词:
+索尼, 索粉, 粉丝, 上, 业务, 破产, sony, 人, 会, 产品
+jieba-关键词:
+平井, 一夫, 粉丝, 魅力, 产品, 中国, 业务, 财年, 偶像, 成都
+KeyExtract-关键词:
+索尼, 索粉, 平井, 一夫, 魅力, 一个, 财年, 粉丝, 赏, 亿日元
+TextRank4ZH-关键词:
+平井一夫, 索尼魅力, 索尼中国
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+名字——索尼魅力赏, 游戏作品软件销量, 高质量消费电子品产, 索尼游戏业务正式回, 放心——,  游戏销量超,  全球销量超,  款精品 , 款游戏作品, 伙伴合作补完
+Rake 中文关键短语/词
+平井一夫, 营业利润, 游戏, 正式, 明星, 总裁, 改革, 高桥洋, 中国, 利润
+```

+ 17 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output1.txt

@@ -0,0 +1,17 @@
+TextRank4ZH-关键词:
+说, 可能, 去, 会, 比赛, 上, 觉得, 球队, 现在, 大家
+jieba-关键词:
+比赛, 可能, 球队, 觉得, 没有, 时候, 大家, 上港, 看到, 应该
+KeyExtract-关键词:
+一个, 比赛, 说, 都, 球队, 会, 去, 上, 当中, 不
+TextRank4ZH-关键词:
+人觉着, 会去, 觉得可能, 足协杯上, 人说, 可能会, 球队可能, 去说, 上可能, 觉着球队
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+纸手帕盖住口鼻健康城市美, 油品升
+火
+, 海农商银行女足门, 性珠宝品牌集合店, 职业级教练员班, 报量
+鼓点敲打, 路军马投身市场, 冠军世锦赛冠军世界纪录, 红酒生意红酒生意, 主两回合里塞
+Rake 中文关键短语/词
+能量值, 全天候体育, 点球大战, 足球最强音, 上海上港, 个性, 身体状态, 赛季首胜, 广州恒大, 挺有意思

+ 14 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output2.txt

@@ -0,0 +1,14 @@
+TextRank4ZH-关键词:
+阎又文, 傅作义, 身份, 王玉, 人, 组织, 秘密, 和平, 联系, 父亲
+jieba-关键词:
+身份, 组织, 北京, 联系, 情报, 北平, 同志, 解放, 父亲, 秘密
+KeyExtract-关键词:
+身份, 阎又文, 真实, 傅作义, 人, 年, 才, 31, 我党, 和平
+TextRank4ZH-关键词:
+北京和平
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+区保安处参加集训, 北京古城文化古迹免, ——怀念战友阎, 宝山革命革命公墓, 水利部农田水利局副局长, 农业部粮油局局长, 成绩考入山西, 时国家正处, 平解放做, 级组织安排
+Rake 中文关键短语/词
+真实身份, 地下工作者, 身份, 王玉, 北京, 信任, 一直, 阎又文, 我党, 上级

+ 15 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output3.txt

@@ -0,0 +1,15 @@
+TextRank4ZH-关键词:
+业绩, 市场, 机构, 证券, 震荡, 认为, 调研, 公司, 预喜, 医药
+jieba-关键词:
+机构, 业绩, 调研, 市场, 公司, 医药, 预喜, 震荡, 预告, 个股
+KeyExtract-关键词:
+家, 机构, 调研, 业绩, 公司, 市场, 预喜, 中, 上市公司, 医药
+TextRank4ZH-关键词:
+业绩预喜, 机构调研, 预喜公司, 业绩增速, 业绩预告
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+沪深两市集体走强, 太平洋证券首席市场, 机构家数累计超, 机构调研次数超, 期新高
+周, 报盈利水平发现, 季度机构调研家数, 报业绩预告情况, 业绩持续高增长, 报预告增速相
+Rake 中文关键短语/词
+机构调研, 信维通信, 医药生物, 中报业绩, 调研, 机构, 盈利, 个股, 分别, 对象

+ 14 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output4.txt

@@ -0,0 +1,14 @@
+TextRank4ZH-关键词:
+土地, 地方, 会, 财政, 部委, 货币, 改革, 信贷, 继续, 国企
+jieba-关键词:
+土地, 地方, 财政, 部委, 信贷, 可能, 货币, 资产, 继续, 改革
+KeyExtract-关键词:
+年, 土地, 地方, 会, 财政, 一个, 部委, 不, 资产, 货币
+TextRank4ZH-关键词:
+地方财政, 只能继续
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+感谢 @伯通李 , 钢铁水泥煤炭家电汽车, 篇帖子猜测东亚土改, 城投平台搞基建贷款, 担心薅羊毛反, 坐视贬值+通胀, 搞成王安石变法, 高位买盘增加贷款, 须补交市政建设基金, 主动紧缩+疗伤
+Rake 中文关键短语/词
+央地分权, 资产价格, 地方政府, 城市, 库存, 目前, 资产, 长期, 政府, 逻辑

+ 14 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output5.txt

@@ -0,0 +1,14 @@
+TextRank4ZH-关键词:
+杀手, 连环, fbi, 犯罪, 定义, 人, 行为, 理论, 知识, 特征
+jieba-关键词:
+杀手, 连环, 没有, 特征, 犯罪, 理论, 行为, 性格, 定义, 文章
+KeyExtract-关键词:
+杀手, 连环, 一个, 人, 都, 定义, FBI, 划分, 说, 不
+TextRank4ZH-关键词:
+连环杀手, 说说
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+越搜索资料越发现案件, ↑↑↑↑↑, 塞萨雷·龙布罗梭, 梅泽·塔菲特, 英文名词——, 童免受性犯罪, 学早期研究, 份国外调查, 环杀手计划性强, 机挑选素
+Rake 中文关键短语/词
+无情型人格障碍, 特征, 理论, 犯罪者, 办法, 被害人, 时间, 类型, 比较, 前段

+ 15 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output6.txt

@@ -0,0 +1,15 @@
+TextRank4ZH-关键词:
+中国, 全球, 美国, 品牌, 中兴, 手机, 电子, 市场, 产业, 人
+jieba-关键词:
+中国, 美国, 品牌, 全球, 电子, 市场, 产业, 手机, 制造, 产品
+KeyExtract-关键词:
+中国, 都, 美国, 全球, 品牌, 电子, 人, 芯片, 不, 亿美元
+TextRank4ZH-关键词:
+中国市场, 手机品牌, 占全球, 电子品牌, 中国制造, 芯片产业, 中国人, 手机市场, 中国电子
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+凤凰新闻客户端主笔唐驳虎​​​​, 凤凰新闻客户端主笔唐驳虎
+, 全球化技术-市场布局, 深深融入全球贸易体系, 普洛夫式贬低, 信息-通信技术, 午北京时间晚, 电子整机制造基, 电子整机行业成, 游产业做苦力
+Rake 中文关键短语/词
+新闻, 中国市场, 电子, 中国生产, 中国人, 整机, 时间, 信息, 手机, 半导体

+ 14 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/Sample_Output/Output7.txt

@@ -0,0 +1,14 @@
+TextRank4ZH-关键词:
+索尼, 索粉, 粉丝, 上, 业务, 破产, sony, 人, 会, 产品
+jieba-关键词:
+平井, 一夫, 粉丝, 魅力, 产品, 中国, 业务, 财年, 偶像, 成都
+KeyExtract-关键词:
+索尼, 索粉, 平井, 一夫, 魅力, 一个, 财年, 粉丝, 赏, 亿日元
+TextRank4ZH-关键词:
+平井一夫, 索尼魅力, 索尼中国
+jieba-关键短语:(N/A)
+KeyExtract-关键短语:(N/A)
+Rake4ZH-关键短语:
+名字——索尼魅力赏, 游戏作品软件销量, 高质量消费电子品产, 索尼游戏业务正式回, 放心——,  游戏销量超,  全球销量超,  款精品 , 款游戏作品, 伙伴合作补完
+Rake 中文关键短语/词
+平井一夫, 营业利润, 游戏, 正式, 明星, 总裁, 改革, 高桥洋, 中国, 利润

+ 1199 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/stoplist/中文停用词表(1208个).txt

@@ -0,0 +1,1199 @@
+人民
+末##末
+啊
+阿
+哎
+哎呀
+哎哟
+唉
+俺
+俺们
+按
+按照
+吧
+吧哒
+把
+罢了
+被
+本
+本着
+比
+比方
+比如
+鄙人
+彼
+彼此
+边
+别
+别的
+别说
+并
+并且
+不比
+不成
+不单
+不但
+不独
+不管
+不光
+不过
+不仅
+不拘
+不论
+不怕
+不然
+不如
+不特
+不惟
+不问
+不只
+朝
+朝着
+趁
+趁着
+乘
+冲
+除
+除此之外
+除非
+除了
+此
+此间
+此外
+从
+从而
+打
+待
+但
+但是
+当
+当着
+到
+得
+的
+的话
+等
+等等
+地
+第
+叮咚
+对
+对于
+多
+多少
+而
+而况
+而且
+而是
+而外
+而言
+而已
+尔后
+反过来
+反过来说
+反之
+非但
+非徒
+否则
+嘎
+嘎登
+该
+赶
+个
+各
+各个
+各位
+各种
+各自
+给
+根据
+跟
+故
+故此
+固然
+关于
+管
+归
+果然
+果真
+过
+哈
+哈哈
+呵
+和
+何
+何处
+何况
+何时
+嘿
+哼
+哼唷
+呼哧
+乎
+哗
+还是
+还有
+换句话说
+换言之
+或
+或是
+或者
+极了
+及
+及其
+及至
+即
+即便
+即或
+即令
+即若
+即使
+几
+几时
+己
+既
+既然
+既是
+继而
+加之
+假如
+假若
+假使
+鉴于
+将
+较
+较之
+叫
+接着
+结果
+借
+紧接着
+进而
+尽
+尽管
+经
+经过
+就
+就是
+就是说
+据
+具体地说
+具体说来
+开始
+开外
+靠
+咳
+可
+可见
+可是
+可以
+况且
+啦
+来
+来着
+离
+例如
+哩
+连
+连同
+两者
+了
+临
+另
+另外
+另一方面
+论
+嘛
+吗
+慢说
+漫说
+冒
+么
+每
+每当
+们
+莫若
+某
+某个
+某些
+拿
+哪
+哪边
+哪儿
+哪个
+哪里
+哪年
+哪怕
+哪天
+哪些
+哪样
+那
+那边
+那儿
+那个
+那会儿
+那里
+那么
+那么些
+那么样
+那时
+那些
+那样
+乃
+乃至
+呢
+能
+你
+你们
+您
+宁
+宁可
+宁肯
+宁愿
+哦
+呕
+啪达
+旁人
+呸
+凭
+凭借
+其
+其次
+其二
+其他
+其它
+其一
+其余
+其中
+起
+起见
+岂但
+恰恰相反
+前后
+前者
+且
+然而
+然后
+然则
+让
+人家
+任
+任何
+任凭
+如
+如此
+如果
+如何
+如其
+如若
+如上所述
+若
+若非
+若是
+啥
+上下
+尚且
+设若
+设使
+甚而
+甚么
+甚至
+省得
+时候
+什么
+什么样
+使得
+是
+是的
+首先
+谁
+谁知
+顺
+顺着
+似的
+虽
+虽然
+虽说
+虽则
+随
+随着
+所
+所以
+他
+他们
+他人
+它
+它们
+她
+她们
+倘
+倘或
+倘然
+倘若
+倘使
+腾
+替
+通过
+同
+同时
+哇
+万一
+往
+望
+为
+为何
+为了
+为什么
+为着
+喂
+嗡嗡
+我
+我们
+呜
+呜呼
+乌乎
+无论
+无宁
+毋宁
+嘻
+吓
+相对而言
+像
+向
+向着
+嘘
+呀
+焉
+沿
+沿着
+要
+要不
+要不然
+要不是
+要么
+要是
+也
+也罢
+也好
+一
+一般
+一旦
+一方面
+一来
+一切
+一样
+一则
+依
+依照
+矣
+以
+以便
+以及
+以免
+以至
+以至于
+以致
+抑或
+因
+因此
+因而
+因为
+哟
+用
+由
+由此可见
+由于
+有
+有的
+有关
+有些
+又
+于
+于是
+于是乎
+与
+与此同时
+与否
+与其
+越是
+云云
+哉
+再说
+再者
+在
+在下
+咱
+咱们
+则
+怎
+怎么
+怎么办
+怎么样
+怎样
+咋
+照
+照着
+者
+这
+这边
+这儿
+这个
+这会儿
+这就是说
+这里
+这么
+这么点儿
+这么些
+这么样
+这时
+这些
+这样
+正如
+吱
+之
+之类
+之所以
+之一
+只是
+只限
+只要
+只有
+至
+至于
+诸位
+着
+着呢
+自
+自从
+自个儿
+自各儿
+自己
+自家
+自身
+综上所述
+总的来看
+总的来说
+总的说来
+总而言之
+总之
+纵
+纵令
+纵然
+纵使
+遵照
+作为
+兮
+呃
+呗
+咚
+咦
+喏
+啐
+喔唷
+嗬
+嗯
+嗳
+~
+!
+.
+:
+"
+'
+(
+)
+*
+A
+白
+社会主义
+--
+..
+>>
+ [
+ ]
+
+<
+>
+/
+\
+|
+-
+_
++
+=
+&
+^
+%
+#
+@
+`
+;
+$
+(
+)
+——
+—
+¥
+...
+‘
+’
+〉
+〈
+…
+ 
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+二
+三
+四
+五
+六
+七
+八
+九
+零
+>
+<
+@
+#
+$
+%
+︿
+&
+*
++
+~
+|
+[
+]
+{
+}
+啊哈
+啊呀
+啊哟
+挨次
+挨个
+挨家挨户
+挨门挨户
+挨门逐户
+挨着
+按理
+按期
+按时
+按说
+暗地里
+暗中
+暗自
+昂然
+八成
+白白
+半
+梆
+保管
+保险
+饱
+背地里
+背靠背
+倍感
+倍加
+本人
+本身
+甭
+比起
+比如说
+比照
+毕竟
+必
+必定
+必将
+必须
+便
+别人
+并非
+并肩
+并没
+并没有
+并排
+并无
+勃然
+不
+不必
+不常
+不大
+不但...而且
+不得
+不得不
+不得了
+不得已
+不迭
+不定
+不对
+不妨
+不管怎样
+不会
+不仅...而且
+不仅仅
+不仅仅是
+不经意
+不可开交
+不可抗拒
+不力
+不了
+不料
+不满
+不免
+不能不
+不起
+不巧
+不然的话
+不日
+不少
+不胜
+不时
+不是
+不同
+不能
+不要
+不外
+不外乎
+不下
+不限
+不消
+不已
+不亦乐乎
+不由得
+不再
+不择手段
+不怎么
+不曾
+不知不觉
+不止
+不止一次
+不至于
+才
+才能
+策略地
+差不多
+差一点
+常
+常常
+常言道
+常言说
+常言说得好
+长此下去
+长话短说
+长期以来
+长线
+敞开儿
+彻夜
+陈年
+趁便
+趁机
+趁热
+趁势
+趁早
+成年
+成年累月
+成心
+乘机
+乘胜
+乘势
+乘隙
+乘虚
+诚然
+迟早
+充分
+充其极
+充其量
+抽冷子
+臭
+初
+出
+出来
+出去
+除此
+除此而外
+除此以外
+除开
+除去
+除却
+除外
+处处
+川流不息
+传
+传说
+传闻
+串行
+纯
+纯粹
+此后
+此中
+次第
+匆匆
+从不
+从此
+从此以后
+从古到今
+从古至今
+从今以后
+从宽
+从来
+从轻
+从速
+从头
+从未
+从无到有
+从小
+从新
+从严
+从优
+从早到晚
+从中
+从重
+凑巧
+粗
+存心
+达旦
+打从
+打开天窗说亮话
+大
+大不了
+大大
+大抵
+大都
+大多
+大凡
+大概
+大家
+大举
+大略
+大面儿上
+大事
+大体
+大体上
+大约
+大张旗鼓
+大致
+呆呆地
+带
+殆
+待到
+单
+单纯
+单单
+但愿
+弹指之间
+当场
+当儿
+当即
+当口儿
+当然
+当庭
+当头
+当下
+当真
+当中
+倒不如
+倒不如说
+倒是
+到处
+到底
+到了儿
+到目前为止
+到头
+到头来
+得起
+得天独厚
+的确
+等到
+叮当
+顶多
+定
+动不动
+动辄
+陡然
+都
+独
+独自
+断然
+顿时
+多次
+多多
+多多少少
+多多益善
+多亏
+多年来
+多年前
+而后
+而论
+而又
+尔等
+二话不说
+二话没说
+反倒
+反倒是
+反而
+反手
+反之亦然
+反之则
+方
+方才
+方能
+放量
+非常
+非得
+分期
+分期分批
+分头
+奋勇
+愤然
+风雨无阻
+逢
+弗
+甫
+嘎嘎
+该当
+概
+赶快
+赶早不赶晚
+敢
+敢情
+敢于
+刚
+刚才
+刚好
+刚巧
+高低
+格外
+隔日
+隔夜
+个人
+各式
+更
+更加
+更进一步
+更为
+公然
+共
+共总
+够瞧的
+姑且
+古来
+故而
+故意
+固
+怪
+怪不得
+惯常
+光
+光是
+归根到底
+归根结底
+过于
+毫不
+毫无
+毫无保留地
+毫无例外
+好在
+何必
+何尝
+何妨
+何苦
+何乐而不为
+何须
+何止
+很
+很多
+很少
+轰然
+后来
+呼啦
+忽地
+忽然
+互
+互相
+哗啦
+话说
+还
+恍然
+会
+豁然
+活
+伙同
+或多或少
+或许
+基本
+基本上
+基于
+极
+极大
+极度
+极端
+极力
+极其
+极为
+急匆匆
+即将
+即刻
+即是说
+几度
+几番
+几乎
+几经
+既...又
+继之
+加上
+加以
+间或
+简而言之
+简言之
+简直
+见
+将才
+将近
+将要
+交口
+较比
+较为
+接连不断
+接下来
+皆可
+截然
+截至
+藉以
+借此
+借以
+届时
+仅
+仅仅
+谨
+进来
+进去
+近
+近几年来
+近来
+近年来
+尽管如此
+尽可能
+尽快
+尽量
+尽然
+尽如人意
+尽心竭力
+尽心尽力
+尽早
+精光
+经常
+竟
+竟然
+究竟
+就此
+就地
+就算
+居然
+局外
+举凡
+据称
+据此
+据实
+据说
+据我所知
+据悉
+具体来说
+决不
+决非
+绝
+绝不
+绝顶
+绝对
+绝非
+均
+喀
+看
+看来
+看起来
+看上去
+看样子
+可好
+可能
+恐怕
+快
+快要
+来不及
+来得及
+来讲
+来看
+拦腰
+牢牢
+老
+老大
+老老实实
+老是
+累次
+累年
+理当
+理该
+理应
+历
+立
+立地
+立刻
+立马
+立时
+联袂
+连连
+连日
+连日来
+连声
+连袂
+临到
+另方面
+另行
+另一个
+路经
+屡
+屡次
+屡次三番
+屡屡
+缕缕
+率尔
+率然
+略
+略加
+略微
+略为
+论说
+马上
+蛮
+满
+没
+没有
+每逢
+每每
+每时每刻
+猛然
+猛然间
+莫
+莫不
+莫非
+莫如
+默默地
+默然
+呐
+那末
+奈
+难道
+难得
+难怪
+难说
+内
+年复一年
+凝神
+偶而
+偶尔
+怕
+砰
+碰巧
+譬如
+偏偏
+乒
+平素
+颇
+迫于
+扑通
+其后
+其实
+奇
+齐
+起初
+起来
+起首
+起头
+起先
+岂
+岂非
+岂止
+迄
+恰逢
+恰好
+恰恰
+恰巧
+恰如
+恰似
+千
+千万
+千万千万
+切
+切不可
+切莫
+切切
+切勿
+窃
+亲口
+亲身
+亲手
+亲眼
+亲自
+顷
+顷刻
+顷刻间
+顷刻之间
+请勿
+穷年累月
+取道
+去
+权时
+全都
+全力
+全年
+全然
+全身心
+然
+人人
+仍
+仍旧
+仍然
+日复一日
+日见
+日渐
+日益
+日臻
+如常
+如此等等
+如次
+如今
+如期
+如前所述
+如上
+如下
+汝
+三番两次
+三番五次
+三天两头
+瑟瑟
+沙沙
+上
+上来
+上去
+一个
+月
+日
+\n

+ 116 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/stoplist/中文分隔词词库.txt

@@ -0,0 +1,116 @@
+和
+的
+虽
+仅
+跟
+与
+既
+同
+及
+而
+况
+况且
+何况
+乃至
+则
+乃
+就
+而
+便
+于是
+然后
+至于
+说到
+此外
+像
+如
+一般
+比方
+接着
+却
+虽然
+但是
+然而
+而
+偏偏
+只是
+不过
+至于
+致
+不料
+岂知
+原来
+因为
+由于
+以便
+因此
+所以
+是故
+以致
+或
+或者
+还是
+亦
+非
+即
+不是
+就是
+若
+如果
+若是
+假如
+只要
+除非
+假使
+倘若
+即使
+假若
+要是
+譬如
+像
+好比
+如同
+似乎
+等于
+不如
+不及
+与其
+若
+则
+虽然
+可是
+虽然
+固然
+尽管
+纵然
+即使
+不但
+不仅
+而且
+何况
+并
+且
+不管
+只要
+除非
+以
+以便
+正在
+以免
+为了
+了
+仍
+。
+,
+;
+:
+?
+!
+&
+’
+‘
+”
+“
+、
+《
+》

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/Abstract.txt


+ 1 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/Satellite.txt

@@ -0,0 +1 @@
+中国发射了一枚新的卫星,将在未来用于帮助中国的太空探测器从月球背面登陆,而那是人类从地球上从未见过的月球表面。中国国家航天局公布消息,北京时间周一(5月21日)5时28分,“鹊桥号”中继卫星在西昌卫星发射中心升空。这枚用中国古代神话牛郎织女相聚的“鹊桥”命名的卫星,将作为中国探月任务的第一步,其作用是为未来的嫦娥四号月球探测任务提供地月之间的中继通信。它将在距离地球40多万公里(约30万英里)的轨道上运行,也是世界上第一枚在该轨道上运行的人造卫星。“鹊桥”进入运行轨道之后,中国将计划向月球背面发送探测器。中国声称,这一任务将会在2018年底“择机实施”。如果中国成功令探测器在月球背面登陆,将是人类第一次月球背面探索任务。1959年,苏联“月球3号”(Luna 3)太空船最早拍摄到月球背面的照片。九年之后的1968年,美国“阿波罗8号”太空船围绕月球飞行时,船舱里的宇航员是最早亲眼观察到月球背面的人类。

+ 1 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/ZTE.txt

@@ -0,0 +1 @@
+搜狐科技5月22日,据消息人士称,美中就解决中兴通讯相关争端大致达成一致,美国将取消中兴通讯销售禁令,根据讨论的协议维持其业务。 消息人士还称,中兴通讯将被要求大规模调整管理层和董事会。中兴回应称消息属实。此前5月20日凌晨中美两国发表联合声明内容,表示不打贸易战,并停止互相加征关税。随后美国国家经济委员会主任库德洛(Larry Kudlow)接受采访时称,商务部长罗斯(Wilbur Ross)正在重新审视对中兴的制裁,但中兴自身需作出改变,包括换领导层、换董事会等。自4月中,美国商务部上个月以违反美国政府制裁禁令为由,宣布禁止美国公司向中兴通讯出口电信零部件产品,期限为7年。此前美国总统特朗普日前发推称,其正与习近平主席合作,帮助中兴迅速恢复业务,这一表态被视作中兴通讯禁令有望解除的关键信号。

+ 1 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本1.txt

@@ -0,0 +1 @@
+智慧型合約(英語:Smart contract)是一種特殊協定,在區塊鏈內製定合約時使用

+ 219 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本2.txt

@@ -0,0 +1,219 @@
+现在是北京时间12点整。
+动听,全天候体育第一台,这里是fm94.05星,体育广播
+因为那是否这个意思bb6在那里不报量
+鼓点敲打出生活的热情
+足球悦动去生命的激情
+我爱足球,也爱音乐,收听fm94.05星体育广播为上海女足加油为上海足球助威,我十上海农商银行女足门将赵丽娜
+5月22日晚,2018国际田联钻石联赛,上海站再度重磅来袭,奥运会冠军世锦赛冠军世界纪录,保持者,奇景形成为网管而来。
+苏炳添谢震业,巩立姣、薛长锐等中国名将,也将携手出战,叹为中国军团的荣耀之光
+多年意识,只为一句突破
+一起来感受田径运动的激情
+共同见证中国力量的崛起
+5月12号钻石联赛,上海体育场等你光临。
+这里有最权威的足球资讯,这里有最强劲的足球声音,这里有最全新的梦幻组合,求爱绿茵场来自足球最本初的爱
+每周六中午12点至13点,小松小尤与你共赴足球盛宴,到处绿茵场的点点滴滴
+动听,全天候体育第一台,欢迎各位继续来锁定我们的五星体育广播、fm94.0来收听这一周,为各位大能全运场,各位好,我是小松,我是小优节目呢,继续录播的方式和各位收音机前的听众朋友,一起来分享一下,在刚刚结束的足协杯第五轮的比赛那上海两支球队整体这样的一个发挥,因为此前我们看到身心和关的比赛,结束了更早一些。
+也是最终很遗憾,不敌关这样的话,也止步到了足协杯之旅,应该说已经结束了,那对于上海两强来说呢,又去中超两强是大家关注度更高而且申花这边呢,包括上港在之前的这一周呢,也成为了大家很关注的一点,为什么这么想,其实说到上港回想了恒大,那恒大这个比赛和上港的比赛,其实有这么一点如出一辙的味道都
+在点球大战过程当中,但是结果是全然不同的,恒大是止步点球大战而上港式成功越过了点球大战,从而挺进到了接下来,这一轮面对对手也是曾几何时淘汰申鑫的北京关,所以我觉得可能这个比赛足协杯很多人都说冷门迭爆的温床,今天很想听听手游对此是怎么来看,甚至一段时间吗?
+大家都在说,会不会上岗,在三线作战的过程当中,现在
+有那么一点疲态,尽显是不是对于接下来的比赛过程当中,到底如何去取舍,也成为了一个大家比较关心的问题,当然对于咱们申花来说呢,在这一轮的联赛过程当中,即将客场赢得对阵广州富力应该说也是吸引了很多球迷的关注,尤其在职不足以谓之后可能很多球迷也希望啊专注于联赛的申花会有更加好了一个发挥和表现那
+在上轮联赛过程当中呢,其实没有让大连一方去拿到赛季首胜,结果很有意思的事,你会发现这个比赛和比赛之间都很用联系啊,任一,方还是拿到了赛季首胜,而且是在足协杯上对吧,我觉得这挺有意思,今天节目都会和各位收音机前的听众朋友一起来分享那么最起码马上来到我们的足球最强音,先来和各位一起分享一下刚刚在足协杯的
+第五轮,上海上港和北京人和的这场焦点大战马上来到我们这一周的足球最强音喧嚣的呐喊。
+清脆的哨音,激情的解说,这些都是绿茵场上最美的声音。
+但是,这还不够聆听足球最强音
+从这一刻开始
+欢迎出来,这里是正在为您播出的茶林场,各位好,我是小松,我是小又马上来关注足协杯的比赛,应该说呢,提到足协杯那此前是申鑫和申花在第四轮的过程当中啊,都接连遭到了淘汰,尤其对于申花来说,作为卫冕冠军的身份确实引发了很多球迷的关注,当然他还寄希望于接下来中超联赛球队会有一个比较好。
+发挥和表现,当然,对于上港来说呢,现在依旧是多线作战,而且据了解,好像有一个不完全统计,是4支征战亚冠球队当中,其实也是排名最好的几个球量中,唯一还保有三线作战资格的一支球队,所以这场比赛呢同样引发了很多人的关注,又是以强大若就是理想当中呢,尤其对阵北京人和
+升班马的球队,当然其实看到这场比赛,最后呈现出这样的一个结果,看得出来确实虽然轮换了啊,4名主力的上海上港,但在比赛过程当中还是非常的艰难,其实你看这一轮的比赛其实申花是较早议论此事在第五轮的时候那么,就被淘汰掉了,那么当时这个可能大家事情
+发了一个爆点,实际上难道说一个中超冠军球队,哪怕就多打了一轮,在第六轮被淘汰掉,不应该也同样引发暴跌门,可是你看就没有为什么,因为大家真的是相对来讲广州球迷也好,广州恒大也好,他很清楚三线作战的话,对这支球队的压力太大太大了,那么可
+能那是他有所取舍,即使有些人不愿意面对这个问题,说他真的在足协杯上就是能力不行了,实力不行了,那也要知道他是因为第一套阵容,第一的主力阵容,他现在也没有这个能量值,连续的这样的争战,所以他才轮换了阵容那么轮换阵容之后,导致他
+出现了一些没有办法的这种不可挽回的结果,在这我插一句,因为我之前看到小的朋友圈,其实,对于广州恒大的被淘汰,甚至上海上港的惊险晋级生的这一轮的足协杯,为什么产生这么多冷门,都会有自己的一些观点,这其中引发我自己去关注的就是提到了恒大的阵容,刚才其实小卫提到了9名优23的球员进入到
+名单当中,4到5名的说,23球员出现在首发名单当中,其实这个阵容刚才小尤提到这一点,我就想到这个朋友圈当中内容就说到了这场比赛,卡纳瓦罗先生在排除这样的一套阵容,时,任何结果都会接受对吧行我,绝对的第一,对,其实我昨天真的是在非常困难的情况下,雾时候大胖子
+要睡了,睡前要真的和大家分享这一点,为什么怎么说,为什么我强调实际上我是在上周就是苏宁客场打完广州的这个比赛之后,我有了这么深刻的一个感受,其实我,一直在各处都没有讲,在广播当中其实我就透露吧,那天呢苏宁打完这个广州恒大的比赛之后,其实
+我在混合采访区就跟着我的老朋友,直接结束工作走了,我就跟郜林一起出去,然后跟他的家人宝宝一块儿去吃了个火锅,那么实际上我怎么感受到的这种阵容上,必须要轮换了他就跟我说她说真的是现在感觉身体非常疲劳,特说三线做
+占很大,如果都觉着累的话,那其他另外三支球队不可能觉着不累,他说了一个小小的细节,我觉得这个地方其实我考虑再三吧,我觉得不讲是谁了,他说这一天就是打完跟苏宁这个比赛的时候,其实他们是成人的那场比赛,苏宁打的是更好,但是他们确实很有运气。
+也蛮强的呢,他们说是卡纳瓦罗先生呢,在开准备会的时候,跟大家说了,没事儿,你们一定要咬紧牙关,咱们现在是确认因为他们人员上外援有好多不能用的那么包括实际上他们的内援也很疲劳,说,但是你们要咬住牙关说这个最后一分钟进球也是进球也会赢得比
+在路胜利,他们下了比赛以后,那场比赛真的是最后的时刻,最后一分钟的绝杀,所以他们下来比赛也说要跟卡帅讲,以后呢,就说比赛第一分钟进球比赛就能够赢下来,所以这个呢是一个笑话,但他同时讲了另外一件事情,你听完就知道现在这个状况
+到什么程度,他说,有人在洗澡的时候,看见,有一个椅子,然后就把这个椅子拿过来坐着洗,原因是觉着真的累太漏洞,对的就是洗澡就比赛之后的这个洗澡,其实当时是说到了是谁,但是我觉得这里我们就省略这咕噜,但是讲这块的原因就是我从那一刻
+就开始体会到了广州恒大,已经很清楚了,自己到底在三线作战的过程当中,其实体能已经到了一个什么样的状况,但是为什么,我又生说到了我深深的感受到了广州恒大对于这个中超联赛冠军的这个渴望和重要性,以及他这种坚定不移的决心。
+因为他们提到了一点中超前五轮,或者中超打到第八轮的时候,你领先五个积分,还是几个积分,这都不重要,要看中超第25轮的时候。
+谁还有能力领先5个积分,这个话说的时候其实相当有底气的,也就是说根本就用现在的态度,就是不在意,现在谁在领跑而旨在以之后的情况会是怎样的,就话里有话的的,所以我当时从那个
+开始,我就觉着懂得取舍,懂得知道,在什么样的时间,以最好的一个方式赶紧把有些放下的,该放下的放下,其实足协杯呢,确实有一定的偶然性,因为他只打7轮的比赛,而且是要从第六轮开始才是主课主课这样去打,确实比赛打
+很少人次少,场次也少那么看下来,可能呢,消耗的精力并不多,但有一个问题是,你要考虑到就是也是我昨天很实实在在地写在了那个朋友圈里的,就是足协杯
+只有冠军有意义,从第二名到最后一名,你们千万要注意排名可以不分心后,我就说我开了个玩笑说可以按姓氏笔画来排,因为真的就是你整个这个过程当中,除了当然我也一开始的第一句话就讲了,其实,它是根据各自球队的不同。
+需要来决定,他要在足协杯上做什么样的一种,就是战略出来就打这个比赛,为什么这么说,因为有一些保级球队,现在已经赶紧回去保级了,那么还在这个保级圈里头,并且还打足协杯的话那么这种球队大家看到没有本土教练带队的都是外教
+对对对外教带队就其实外教的感觉,就是我不管中超联赛最后达到什么样的情况,我在每一线上只要我打出一部分,成绩来呢,都是我带队的功劳,所以呢,足协杯呢,你看到也是会看到曼萨诺先生还是非常的兴奋,尽管其实大家会说她在阵容上也
+有一定的小小的微调,可能也看出了一些,就是可能想要让大家休息一下的一个状况,和你看他也是还是会对这个比赛非常非常的重视,最后赢球的那一刻也会是欣喜若狂,那种状态为什么就是那不管怎么样,就算是之后会下课,就算是之后这个赛季这支球
+对可能在保持着路上走得非常非常痛苦,但是他会觉着我带队的时候,这支球队是战胜了广州恒大而踩进了八强足协杯,取得这也是一种乘机,这也是一份荣耀,所以外教带队呢,还包括一方可能接下来要马上要面临到
+成亮澄,知道所带的这个四川九牛那么这些比赛其实都是让我们看到
+他是在每一个不同层面上,这支球队呢,会对足协杯的成绩或者说,哪怕不是冠军的,这个成绩是有所追求的,但是如果对于整个比赛,或者对于三线作战,有非常清楚的现在俱乐部的一个定位,球队的一个定位,1个目标的话,那么看得到,其实
+两头就已经很明显了,就是我充灌的有冲关的想法,然后我我记得有宝鸡的想法,就是这样,所以我觉得这个价行恒大不是说对于上海也好啊,包括对于咱们申花来说,面对比赛,尤其在多线作战的一个状态之下,我们确,实如何去要要去要去放弃或者怎样,但我觉得至少恒大他有这样的一个
+经验和底气在,而且我觉得哪怕是他在排出这套阵容的时候,他也有接受结果的这颗心呐,我觉得他已经做好了这样的一个准备,其实我们在看了恒大的比赛的时候,为什么说和尚了比赛很像,因为在比赛过程当中都遭遇了很大的困难,尤其阵容方面都产生很大的一个变化,甚至影响很大之后啊来一个外援在场上,所以我觉得都是
+一个倒在点球大战,1个在点球大战过程当中,依靠颜骏凌神勇的发挥啊,惊险的晋级,所以我觉得都是面对相对来说,可能之前在联赛过程当中,如果去遭遇这个对手,在对公过程当中都会占尽优势,这样的一个情况,所以我觉得这个比赛对于上港来说去借鉴恒大更多的是接下来再多线作战的过程当中,对于佩拉
+也好,对于乘客记录,对这些队员的状态如何更好的去调整,毕竟现在在三线作战的一个前提之下,尤其在18天有5场比赛,这样的一个亲密赛场上真美一线说难听著,这都不能丢就你接下来,对于亚冠的鹿岛鹿角也好,对于接下来贵州苏宁的中超联赛也好,甚至这个周末其实我们看到马上要
+迎战的对手,我就变成了足协杯的对手,所以我们从呃四战天津权健斯坦、广州恒大队现在演变成四单,北京关那对于上海上港来说,所以我觉得这个比赛其实每一年为什么我觉得特别有意思的原因,也在于此当然我们说回到上港这边其实看到这场比赛的艰难程度,也跟阵容啊,包括其实佩拉赛后以前
+强调了小写的搞脏容易体现出来的就是这个连续度,包括可能仅打时间等等一系列这个问题,其实,之前提到过保护可能看为r视频裁判这个情况也是会打乱比赛的节奏,对于上港甚至对于任何球队都可能都起到一个特别好的作用,但这肯定就是在比赛当中必然会出现的一些问题,那对于上港来说接下来
+我们也必须得面临这个问题,就最近的一段时间,我们客观来讲球队的整体状态啊,包括整体的这种进攻状态,确实受到了一些影响,也遭遇到了一些挑战。
+我不知道效果怎么来看待这个问题
+佩雷拉是先生给出解释,我记得非常非常清楚,他说我们现在的球队,你看不是在一个飞行的过程当中,在就是在一个比赛当中,那么,实际上是没有办法的比赛中恢复是吧,就是这俩就没有办法去做一些技战术方面的磨合的演练,其实很大程度上他是认为现在大家是太
+疲劳了,等于他也是说没有时间去做一些备战,而是就是真的就是去打比赛,没,有被战争的任何一个对手,现在被展示什么备战就变成能以把身体状态尽快调整到一个,还有兴奋度的状况就不错了,活力所以他就觉得这支球队现在是没有兴奋度面对比赛的时候,可能刺激不起来这
+总感觉了,已经都,所以你看比赛会迟迟破不了门,或者要进入到这样,就让人吊起来,的这种很惊心动魄的这种点球大战当中去那么这是他的感受,那么我看到媒体同行们也有再说,可能就是很多人都在说上港的板凳,阵容怎样怎样怎样,我觉着如果上
+党的板凳阵容在中超赛场上还算弱的话,那我觉着这个16家俱乐部里边也不知道到底谁强呢,其实看着很鲁能的储备,很多,或者说这个恒大的储备很多,但你要知道报名人数就放在那里30个报名人数你没报进来的,你人再多,他也不能随便来打比赛。
+对吧,而且他有外援名额的这个限制,包括有二三队员的报名的数量,所以相对来讲不要再去说什么板凳能力,或者怎么样,因为今天我也公开着在一个这个朋友圈的一个同行的朋友圈儿底下就写上了,我就说真是了,我说这我都不知道你们是怎么想的,为什么三线非得都要
+小强,你们所说的这个人员充足的这种三线强,是指一个俱乐部一支球队,里面是得有三个主教练,外加三组11个人的主阵容针对三条战线,去打吗,那可以我觉着,但如果不是那样的话,其实各种磨合就这些人的话,你说他连续
+之间练都没有一块儿练,你就给他捏上去上去,这上去,这11个,他能好吗,其实昨天就微调了几个位置,但有的时候你就会感觉就微调了,这么几个位置,这个球队就没有办法,没有发力点呢,你就感觉那个吉尔好像刺激不上就使不出来那种感觉,那这个状况之下,其实有的时候我还是说法,回头来。
+我,我真的认为就是要有底气,要有正的那种能量值到达,还有就是希望各界包括媒体也,好包括球迷也好不要浮躁,就是真的,如果你的球队你所钟爱的这支球队,他退出这一线赛场的这个冠军争夺战的时候不要马上就把这支球队一下子
+一到那种好像站在悬崖边,儿上,不要把他逼到那样的程度上去,所以说也可能能慢慢会好起来,我们真还是得做好一个,就是各种心理准备,希望这支球队你到底想他在哪一线赛场上证明自己,你要搞清楚,如果他在其他的这个战线当中出现一些状况的时候,轻
+一不要去指责他,因为并不是我们想象的那么简单,板凳阵容意味着什么,板凳阵容意味着坐在那个板凳上,不天天打比赛也是一个凉凉的状态,即使30个都是国脚盈有11个之外的那几位,都是量,量那什么意思就
+都是埃尔克森先生,请你要看到不长时间,不打比赛,其实要保持一个状态,也真的蛮难的,所以我一直都觉着我对他是充满这种尊敬之情的,我特别赞同小游的说法,因为我觉得看过这几场比赛尤其最近这几场比赛一直被球迷拿出来提,因为是和
+前面形成一个非常鲜明的对比啊,从六连胜到墨尔本胜利的这场比赛开始往中间,我们应大行之水的就不说了剩下的等于5场比赛里的四场球,90分钟内也没没没赢球而,且还遭遇了我们赛季首败,不是说我们不能说我只是说确实这连续的这段时间,我们遭遇了一些困难当然这肯定跟佩拉先生所
+说了,包括刚才有提到了这些原因,挂钩,但是我觉得对于球队来说很重要的一点就是它受到了很多因素的这种限制,包括,球员在场上的这个表现是不是真正意义上来,是基站,而且来之际上又是否能跟真正意义上权力串联起来,加上其实之前的这一轮的最为的比赛球队还遭遇了一个困难,就是奥斯卡的这个
+受伤离场,稍后其实行小的也跟我们来更新一下,最新的奥斯卡,这个情况据了解,应该说没事儿就包括吴磊这边,我觉得这可能都是在比赛场上出现的问题,所以可能昨天我在采访结束了之后啊,很多人也跟我再聊报,可能请教很多老师求你有这样的一,个心态就是我们很害怕,害怕什么呢,就是虫草覆辙,联系
+上个赛季,其实我们在三千过程当中,表现都还是很强势的。
+到目前为止,有人说佩特拉的战术呢,好像大家已经开始研究了,有针对性的这种部署了八九轮联赛,踢完了,基本上知道你的三板斧,他大体是个什么情况,看有什么后手,这是对于佩特拉的挑战,对于球队的挑战还有人说我们就专心打打一线打两线就我觉得不用把全部精力放在这些有的时候你看作业
+其实预备队也可以打一打呀,是吧,年轻对我像小时候可能也听到过类似的这个情况,从你个人的角度也会不会有一些好的建议,甚至跟同行在聊的过程当中,有没有也意识到类似这样的问题
+其实我在客场长春亚泰那场比赛之后,我就有和大家不一样的意见那么大家,当时可能都觉着,好像我看到的时间,你对裁判一样,其实对于手球啊,都有很多很多的讨论,但是我当时也发朋友圈了,我想该讨厌我的人也都看到了,我已经说呢,其实我我有
+到了别人的一张图,一个我的亚太朋友的一张,他们在休息时里面,其实大家非常热闹的一张图,那我倒过来用。
+梦的时候呢我要说的是什么,我迁走这张照片,拿过来用的时候我就讲了,其实那天的那场比赛呢,我觉着,没有什么好多去想的,其实要接受那个失败,而且那场胜利呢,应该属于在那场比赛当中拼得更凶的长春亚泰,而且呢,看得出来亚太的这个训练质量。
+当是非常高的,那么他们目前的这种身体的能量值,都很高,为什么这么说,先不要去讨论,就是到底裁判给了我们什么样的暗亏,或者怎样你要看自己的这个身体状况的话,2分之一球的时候明显是亚泰拼的凶很多的,坚决的很多动作也能做,而且
+钱呢,你看他们也其实呃,我拿的那张图的时候呢,我的那个朋友也在里面说了,说他其实一度拼到了自己,就是失忆了,就是脑子不是那么的清楚,他只记着20分钟的情况,后来是慢慢比赛结束以后,他才慢慢找回来的那其实这个过程当中你能够感受到什么,就是那场比赛亚泰有福
+非常非常强大的一个决心,就是一定要把你拉下马,这个时候并不代表他们的实力,一定在我们之上,但只能说他这一段的一个备战,他的体能的一个储备,或者他集中精力做着一件事情的时候,真的是做得很好,就这,90分钟他确实表现出了他们的质素来那么你在这样的一个情况下
+你去说,这是佩德拉先生,哪里,哪里做得不好,那我想问佩拉建设能给每个人打个针,让所有队员都回到一个最好的竞技状态上吗,其实能看到我们已经尽显疲态了,为什么我其实我记得非常非常清楚,上一次我们在求二人长久有一周之前小村后连线的
+之后,我就输了一句话吧,我一直在回避小熊,一个问题,就是关于我们打打秦致水电厂比赛,到底打得好不好,这个问题其实好不好,我说了最后就是用结果已经去把所有的一球带过去了,那等你两个故事吗?
+等于我也一再的强调了,其实我说了一句话,我觉得大家如果听得到,就听得到,就是我说了,我站在对手重门,原宋振瑜的门后,看不见基本上我们就不大过来,这会让我可着急了这件事情,那你们就应该懂,那就是我们一直在做半场的防守。
+有这样的一个事情,那,其实挤压的那么的厉害,本土队员的这个身体的疲劳程度,你要知道连续的这个非就是像那天,我们其实那天比赛结束之后,郜林和他的家人在吃饭的时候,他就,问了我一句话,那就是说借你觉着累不累,你觉着你天天跟着球队飞来飞去,你哪?
+不累,其实这个话,他问完我,我也其实我在节目当中,有一值得再说,其实真的是累的,你更不要说是队员了,其实精力上心理上各个方面,现在明显是有感觉的,那么其实但是当人觉着恒大也也说到在大家在聊的时候,也说到,就是上港这批队员限真的是在最好。
+的时间段上,二十七八岁,而且越是一起长大的技战术能力,各个方面都是最好的一个时候,但是你架不住他们都是人,他们也会有这种身体状态的一个低谷,一个疲劳期的出现,所以呢,现在这个时候如果说大家还能够从这个语言上
+嗯,去,激励一下球队的话,那么,可能就最好就做这样的事情,那如果说再去做一些败势气的,或者是拼命要帮人家找什么缺陷的话,就不必了,为什么我许中为什么我其实特别少写球评或者怎么样,并不是我看不懂什么我自认为我看得懂,当然也不一定是
+真正看得懂啊,这个也有可能的,还有一点最关键的是我就是认为,当我没有站在别人那个高度的时候,实际先别去讨论别人的事情,因为上港也好,或者其他的球队也好,他在他的领域里面所处的那个位置,已经打到了会
+到了中国足球的一个巅峰状态了我们现在还去批评他的主帅,好不好批,评他的队员好不好,那你说到底
+真是什么事儿嘛,其实他们自己是最专业的人,一定会找到其中的原因,我觉得很重要的一点是,现在的上港的这个精气神不能散之行,其实在很多的采访报道过程当中,我们看到了配出来,对于整个球队,尤其是这方面,其实在赛后提到了很多哦,他其实满意的很多书不一定是技战术方面,它其实就是求
+为了这种拼搏的精神,我觉得这对于上来说,接下来很关键,因为赛程非常的紧密而且都不能用魔鬼来形容了,简直是地狱级别的,这个赛程对吧,每一场比赛其实都不能有失,而且接着又这么解这个周末呢,马上对北京国安在等于租约为8强对阵出炉之后,其实我们看到的是一个对手,其实我们之前在一起玩了一场的节目当中,给大家预测过。
+在这个半区相较于恒大的那个问题,有那会儿还把恒大当作足协杯,至少对于上港来说,潜在的一个大对手,蛋清过了,这一轮的厮杀之后,其实我们看到了这个发生非常大的一个变化,就刚才有提到了,其实你像饿死穿的这支球队啊,我觉得可能成为了
+现在这粑粑是球队当中嘛,最引大家关注了一支球队,甚至很多申花球迷还开玩笑,说,这其实也有很多咱们申花的元素在作为上得以体现了,所以昨天我们是发个朋友圈的时候嘛,就是这个
+程亮先生成指导的四川久留,马上,要对上周军先生抽,从经历的大连一方,其实真的是你会发现,老申花会师哦,这个挺有意思的,而且你要知道四川九牛的主场实际上是在自贡这个接下来给到大
+连一方这场比赛的困难,也是非常非常足的词,共这个地方,你可能听一听,你说旅游可能会经常去你说谁想到过看足,球去哪儿呢,谁想到一场大战要放在那里,论那你要知道这个挺有意思的真的是当然也有可能之后,因为之前他曾经就是考虑过,如果是
+和申花打的话,就是由虹口来申办主场呢,也不知道他之后会不会和乙方这边也有所商量啊,但是看下来,你就会觉得这真的是八强当中之前,我们其实也很清楚,就把它当中一定会有一个中乙球队锁定了这样的一个名额,那么但是没有想到就是成指导,但是成指导确实这些年吗,因为我
+不知道,真的要再读这个职业级教练员班的时候,其实成绩就非常非常的优秀,非常非常的突出,很多人都在说成找再大,对这一块上是很有自己特点的,也很钻营的,所以呢年轻的主帅们其实正用,他们带队的这种成绩在证明很多那么其实这个过程当中我们就
+你看到足协杯对于四川九牛这样的球队,对于惩治到而言,实际上它是一个非常好的平台,它是一个非常好的展现自我的平台,哪怕在中乙联赛当中,可能他们没有马上就能够冲上来的这种可能性,但是他们透过足协杯的赛场已经让很多人记住了他们的名字。
+然后,很多人都看到了他们的实力,也让很多人知道了,原来在四川自贡还有这么一支球队,其实这真的挺重要的,就是足球作为一个载体,其实确实让那个城市让这支球队,也让现在在这个位置上的这些从业者们,其实找到了自己可能一个很好的一个平台上。
+他们带到的一些相应的后续的一些内容,那么这一块上可能对于他们未来,不管是执教什么样的球队,或者是未来有什么样的发展,转会去了其他什么样的球队,这可能都会是有所帮助的,这种,而且绝对大家都不用去回避着,就是一件好事情,我觉得对于四川九牛嗯可以接
+来的比赛来关注一下,当然另外呢,几轮的比赛,其中看到除了上港队国安,让富力对苏宁这同样是一场硬仗了,对吧鲁能这边呢,相对来说可能好一点,对贵州恒丰但不知道贵州航空淘汰了恒大之后,麦帅包括全队上下会不健康才晓得在节目一开始跟我们说的确实感觉这心气儿啊,包括整个精气神儿是没有不一样,所以
+也可以来关注一下,应该说上港和关的这个比赛,因为上港是先客后主两回合里塞,而且6月份7月份的现在很多球迷在算算那个时间就是这个世界杯,建议7到来之前,因为有一个长达将近两个月的间歇期,对于各支球队来说,这个备案呢,调整啊,其实是非常考究和讲究着堆上
+来说呢,在监狱到来之前,这么短的一个时间内,有这么多场密集的比赛,游联系到可能接下来亚冠和中超联赛,这样的一个积分的形式,甚至尤其是联赛,因为现在恒大有这个底气呀,说你一开始笑了笑的好了不一定是能笑到最后,因为为什么这么想的,你看到这个积分形势,其实已经发生了非常微妙的变化,之前领先五分到
+现在缩小为两分,鲁能跟我们就差一分对吧,几轮联赛去人家已经追上来了,所以这个时候可能相对这个整体的背景和形势率上来,说,确实不太有利。
+但是,我们也要看到鲁能也是啊,进了这个足协杯的8强,而且淘汰华夏这场比赛,其实,打得还是非常艰难的,在这种情况之下,为什么我隐隐的感觉鲁能也会也会接下来有一个小小的低谷,世间可能这还不是最可怕的,最可怕的是收心呢,已经在有一线上收信人的广州恒大是
+这不是进步差,马上要开始发起这种反扑,而且可能在之后,他其实迎来他打上港,只检查,也就是阿兰的这个竞赛,也就结束了吗这8场是不是他会有一个比较好的一个形式,可能这需要打上一个问号,而且它确实有底气,也有经验,在这么多年里面相对来讲。
+确实,这支球队可能还是中超赛场也好,牙关赛场也好,你得看下来的话,真的觉着这支球队确实有些能量值,他有的时候他是靠自己球队,这些队员经历的多了,他所累,积的这些,不管是他知道这个时间段该,做什么还是在场上该如何
+面对这种困境,他们都是真的是场上场下,这些都能够做的比较好,有点儿意思呢,所以今年看起来还是恒大跟上港之间吧,可能在这个不管哪一线的冠军争夺战当中,所就
+虽然他已经离开了足协杯,但是要知道后面的这些对手,也都有点意思,因为现在你就会发现每一支球队想的不同,要的也不同,也不知道到底会到一个什么样的程度上,虽然大家也都在说北京国安的表现不是什么太好的,但我们也要看到那天我我其实看了五一那场就是的。
+异常的这个苏宁,跟天津权健那场
+那场比赛看完,我真的是瞬间泪奔,很多人觉着至于吗,这场比赛,可你这让你要知道,当人说点球也没有人能够超越东吴跟上港,大家动物跟上岗,那个好像我们内心里边总有感觉,就是我们知道上海上港一定会战胜对手对吧,就是我们有这么一个底气
+但是那个苏宁打权健那场的时候,你真没错,1加1了,已经就是五轮八过去以后到1加1的时候,谁也没法那个时候你真的就是那个时候你内心就觉着我们觉得那心脏已经跳图制作出那种感觉就是你不知道谁会最终扮演就是那一下子,所以而且那天他
+那是两个门将,其实都没有主动扑出去过任何一粒球打飞,还都是队员打飞的,所以你要看到包括你那个比赛,真的是2比0领先,你觉得90分钟就应该差不多,结果是在90分钟,请一个在补时的最后一分钟又进一个,而且两个神仙球你就真的那个整个瞬间
+见你就觉得脑子就崩了吗,而且我是就是所有向所有,去走向罚点球那个位置的人,觉得都是应该给予他们掌声。
+呃,能承受那样的压力,至少我认为我们在看的这些人里面,没一个人有那么好的心理素质,谁去肯定都是飞雕的,当然我觉得掌声要多给一点能在点球大战中扑出两个点球的类似这样么优秀了,我真的就觉得这门将怎么做到的
+这种的说一说是这个链接,您本赛季就是下地的,这个速度快了太多太多,这个训练上却是看到
+看来,这个训练它体现出来的这种指数,是抢的很厉害,昨天采访舒淇时,赛后包小这边肯定也了解,他就强调了1.1个事情,我刚才提到这个呃判断这一点还有,就是他在判断一个什么事儿呢,下跌速度肯定是要着重加强了,还有就是他判断对方罚球的这个人在提出穷了一刹那。
+他的这个动作,他现在研究这个,所以他其实感觉上真的是在触球那一刹那,他已经做好了一盘好,我们两个对我觉得平衡,如果能达到这一点,如果继续加强,真的是是很多球迷也说了,只要到了点球大战上港队再也不用担心点球大战,对所以以后其他的球队就不要再做这种,我就是想
+把比赛带进点球大战,然后靠运气,然后怎么样去做,就觉得点球大战的时候就没有技战术含量了,其实也不是其实他对这个每个人的心理素质还是有所考验的,能够看得出来签,昨晚算忘算了这个颜骏凌在点球当中,对于上港这种帮助对而且主帅。
+而且,我觉得今天既然你看他,你看他罚丢点球的这个,我觉得也是他,他应该真呢,他就是还是没有没有正确认识他对面到底是谁,这个很重要很重要,没错,这个他确实应该考虑到这些问题,为什么我们说其实跟大家聊一聊就是关于其实那时候说到天津泰达这个
+讲的今天,难道门将自己对他她最像一种,我不是说了嘛,这个送给大家这个小礼物,但是并没有揭开谜底,其实相信就是他听了这个节目,他也不是一时半会儿能变好的,他的,问题其实就是大家都发现了他的高空球和中路得球都肥肠的,但是下去的速度会满意
+但是,上港那天就打在了他的优势上,一个劲儿地就打高75,那么上港后来自己也发现了这个问题,所以呢,有的时候就是这样,你其实你别说我今年,这是看过几场天津泰达的比赛,要是我只认真的去想一下子还真使他下地球,还经常有,就是就是有出现一些小状况。
+嗯时候,所以呢针对你看看现在这个备战备战,已,经到了这种程度了,中超的激烈程度,各个方面来看
+大家都觉得这足协杯是更加好看了,更加激烈了,我倒觉这是因为中国足球太过于现实,太过于残酷太过于急功近利了,才导致了这一线的赛场出现了这么多的状况,所有看看吧,接下来上港马上和国安的这个叫
+高手,其实也是最为两回合比赛一个预言,而且现在在联赛阶段呢,对于国安也好,对于上港来说,游戏对于上港其实是非常关键的,要知道恒大这一轮的对手是大连一方刚刚尝到了足协,为取得赛季首胜的喜悦之后,马上来对阵可能在联赛要孤注一掷,甚至要把全部更多的精力投入到联赛的恒大,所以我觉得这个比赛呢
+其实野马微妙,当然,鲁能这边同样也是虎视眈眈所以,对于上来说的面对北京国安的这场比赛,或将可能成为最近一段时间,真正意义上的一个大的考验,那么在结束这个比赛之后,马上在下周三小区里要去道路道路脚对吧来关注东京来关注这场亚冠的淘汰赛了嗯,同样是先客后主这样的一个赛程,日本球队
+刚刚来说,也不能生去年,其实很遗憾的就是指不在了浦和红钻的这个脚下,所以其实很多人也希望这个比赛呢,上可以顺利的通过在连续了紧密赛程之下,球队到底会呈现一个什么样的状态,甚至可能赔啦更多的去调整球员的精神状态和,身体状态同时能不能尽快的去找到我们六连胜那会儿的内容精气神包括那种
+身体状态,我觉得可能是现在,对于商来说比,较棘手的,一个问题,我们暂且不想足协杯,是应该如何去取舍,至少我们现在晋级了,那接下来,我,觉得,就可能会把更多的精力提升到,可能对阵比赛的这种态度上,一但我始终相信两支球队肯定也是希望全力争胜的,他每一场比赛他其实都是这目的,我有一点我
+觉着我挺,我觉得挺开心的,开心的是什么地方,我觉得挺好的,我倒不像大家那么担心,就是本周打这个北京国安的比赛,我觉着如果表现出来的这样太差一点也不是坏事儿,就是让北京国安搞不清楚到底上海上港的所有能量是怎样的也是件好事儿啊,反正之后是要经过一个小小
+找地休息一个休整的一个时间以后,双方才会有这个第六轮的比赛,主客两场比赛,所以那个时候我觉得只要上港能调整好,就可以,就像晓松说的,因为这一线已经又向前走了一步,而且这种概率已经越来越高的时候,那就坚持下去吧,既然能走的话就一定要好好走下去,而且凹槽
+和物理的整体的恢复情况,也不错,其实昨天我们是看到了在医院,但今天要查自己,也发这个是让我们贴上说了,我已经好吧我,我看他发了一段这个,我是特意上去看了一下,那位边上去了看了大件发了一段母语的,然后我用这个查看翻译看了一下,原来他就是说谢谢大家的这个消息
+诶,那么呢,我已经好了啊,然后花了一个机长的小图,你们翻译过来,我看到的这,个情况我觉得应该说就说明他的他脑袋当时撞了一下子,可能是觉得这是有一点点肯定是会有一些感觉的,并且可能会有轻微的脑震荡的一些反应,呕吐啊或者恶心,但是休息一下之后,这个很快
+还好,就是一个真是万幸,就是只有小硬伤,所以也希望把上这边的、主力球员的伤病问题,可以得到一个很好的解决和恢复,能在对阵北京国安的比赛过程当中,也会展现一个更好的状态,我相信可能在密集赛程之后。
+累了几场球,或者大家也听到了很多关于球类,关于批判这个问题,我相信球员自己都会有一个感受,那我觉得可能在场上,这些球员也不需要去动物园,因为她们也非常清楚,每一场比赛对于他们这个意义,呃,我相信可能接下来的球队呢,会有更好的一个表现,当然我们也希望把下周三在亚冠的这个比赛上对阵鹿岛鹿角的
+理财同样能够传回捷报啊,刚其实也花了点时间和各位一起来分享了一下上海上港这方面的情况,这些我们先进段广告,稍微休息一下,再逛回来之后呢,叫好好来说说咱们申花相较于上港来说呢,三线作战申花这边呢,只有联赛一条战线啊,去更努力的争取,当然我,觉得这可能对于申花来说,增加的
+纯粹和简单的很多,究竟在联赛过程当中,嗯申花现在的位置,其实处的还是非常不错的积分排名情况,所以我觉得完全是有希望在这一轮,对阵广州富力的比赛过程当中,有一个上佳的发挥,当然广州富力呢,接下来在足协杯过程当中也进入到了下一轮和苏宁的比赛多多少少也会牵绊他很多精力,所以对于双方来说能不能把握这样的一个
+机会稍后呢,我们也继续在节目当中,和各位一起来分享这里是正在为您播出的串联场一段广告之后,我们马上回来。
+动听,全天候体育第一台,这里是fm94.05星,体育广播
+疑问,你随便去个research media在那里,付婆娘
+梦your image, area就是弯jar瑞意大利,德国七班牙,美国巴西、日本好多好多国家的品牌个性珠宝,不用出国看吧,不用出国就在上海全部原产地还是各,国当地零售价完全re看遍世界珠宝还不起开
+眼睛冠军re全球个性珠宝品牌集合店,上海万象城一楼小红书,收入5万,空格,只为看小红书门的更多尝鲜美颜。
+爱燃烧创始人咔咔,做客五星体育广播fm94.0,打卡吧,我们说能维持一个稳定的跑步姿势,一定不是你看到的这几块肌肉,它一定是很多肌肉参与进来,才能保持你身体特别稳定,否则的话他一定是一个东摇西晃的一个东西,懦夫永不
+启程弱者死于路上,只有我们一直向前一步不停欢迎锁定9月10七年打卡吧,我们与您不见不散。
+会参会生活,是美一份斗米的行为,晦涩,是挡不住诱惑的味蕾,绽放,由慧参到晦涩。
+唾弃极致,饕餮的奥义绘声绘色,邀您共赏美食与珠宝美学的视觉盛宴,即日起在绘声绘色用餐,就有机会获得全球个性出宝西河店完全未提供的价值,2680元的意大利原产珠宝绘声绘色与您分享精致时尚粤菜的油品升
+火
+这里有最权威的足球资讯,这里有最强劲的足球声音,这里有最全新的梦幻组合,求爱绿茵场来自足球。
+最本初的爱
+每周六中午12点至13点,小松小尤与你共赴足球盛宴,到处绿茵场的点点的历
+欢迎浏览这里,是正在为您播出的全勤场,各位好我是小松,我是小游,来到我们的节目的下半段啊,上班乱呢,我们和各位简单来分享了一下上港在足协杯包括接下来紧密赛程过程当中可能会遇到的一些挑战要各位捡到来解析了球队最新的一些情况,那么借钱马上来关注一下我们的上海绿地申花在上一轮联赛过程当中的神话,这边是1比0
+小胜大连一方应该说,这场比赛呢,也是及时止血,那尤其,在足协杯可能作为卫冕冠军,被淘汰出局了一个前提之下,很多球迷也特别表达了对球队的一些质疑,甚至是不满,当然我们也看到这场比赛对阵大连一方全队依旧是在比较困难的一个前提之下的用拼搏的精神战胜了对手,拿到了非常宝贵的三分。
+而且现在呢,在联赛积分排名也排在第5的位置,相较于整体来看,处理的状态还是不错的,当然这场比赛来结束之后,可能球迷也发表自己的想法,觉得赢球还得靠那个最熟悉的人。
+队长没弄不管靠谁,反正比赛赢了,我觉得都是好事情,大家接着呢,其实还是看到球队可能在有些比赛,其实包括阵痛了一下之后,但那场比赛打一方这场比赛,真得输上海申花承受了太多太多的压力,也所有的人吧,我觉得从吴指导到队员,都感觉到我
+我,我个人是感受这种压力,其实已经超负荷了,问是母说,现在的中国足球太过于急功近利了,就在于其实这支球队你给他那么大的压力之下,你觉得是好事儿,到底还是坏事儿,有的时候这个压力是能成为一种动力,但是任何事情他都有一个尺度,当这个尺度过了之后,这
+种压力,背负前行的路上,有的时候你很难说他到底是好的,还是坏的,它可能会让这个队员的场上真的是瞬间都不知道自己该做什么,或者说可能做什么都是错,这个可能就真的会伤是起而不是一种激励我之前看了小欧的稿子,嗯,其实也
+在强调,尤其对舞蹈来说,他背负了可能是我们没有办法用语言啊,或者是自己什么切身去体会的,这种压力对吧,他自己也说了嘛,因为你能够感觉到其实我,我是觉着从输掉这个南通支云的比赛之后,我没有和我知道微信没有说任何一句话,因为那个时候你
+觉着说什么你都不是安慰别人的,说什么你都是抠别人的伤疤,你以为是要抗,难道你你以为就那个时间,我们就是拼命的去骂这支球队,就刺激到这支球队了吗,不是啊,其实输球和从那一刻退出这个征战的时候其实最大受到最大刺激的,已经是他们自己了,他们自己
+已经在自己的想象画一条大口子了,牛,何必非得去刺激他呢,其实,所以为什么我从这个广州赶回来,当天做了这个中午的航班,赶回来,我一路在飞机上睡睡到下来以后,我是当天晚上我进了家门,只休息了30分钟就马上再出门,就是到虹口区为什么一定要去虹口看这场会
+一方的比赛,其实就是觉着无论如何吧,不说话,但是还是想把一个笑容带到虹口区,向所有看到自己熟悉自己的这些申花人都看到,就是并没有因为球队出现了一些什么样的状况,就是我觉着球队怎样怎样了,我没有觉着球队有任何不好的地方,其实球队在遭遇很多困难的。
+这时候你事实上半支主力队员,就是半只求这个球队就是6名队员,都不在阵中的时候,打什么样的对手,可能都会出现一些问题,也不要说什么比赛,只有什么莫雷诺或者能够进球,或者是怎样怎样,因为这是一个整体的实力问题,如果这支球队当
+当中没有帮助这个队长,没有帮助莫雷诺去传球的人,可能最终的结果也不会是这样的,如果防守做不好莫雷诺进一个球也是没有办法去赢得比赛的,所以我相信场上的所有人场上,其实每一个位置的人都为那场比赛复出了,而且那场比赛。
+其实在赛前,我真的不敢说那句话,就是
+没法想,因为你已经想象你,你怎么去想那场比赛已经变味儿了,因为为什么那场比赛你要说什么随便打一什么长春打印什么输了赢了他都不是什么多大的事儿啊,赢了可能是大事儿输了还好,但是你要知道打的是大连一方,其实我在私底下和同行们开玩笑,我说
+这比赛的真的是让人觉着太遭罪了,为什么遭罪输了就不是输给了大连一方了,输了就是输给了周总了那场比赛就马上变成概念就不一样了,其实承受压力最多的我,相信莫过于主教练和出场的队员们,而且每个队员其实有时候因为我
+我跟情人他一下的微博是互相关注的,我也能看到他的一些就是他发的一些内容,看他也是说前身的那个汤,好像也一直就影响到他疼的,经常是好像马上会反复的去醒来吗,那你,说实际上这些队员们在场上的时候,并没有头上贴个贴说其实我哪儿哪儿哪儿不太舒服,疼的晚上
+睡不着觉,我们进,如果不是不是透过,就是这种社交媒体平台,他的家人如果还写了这样的内容的话,可能我们都不知道我妈觉着这队员好着呢啊,这队员可能就是心情,今天不太好,但实际他不知道是这儿疼,或者那儿疼我们其实自己都不清楚的,有的时候
+给到队员们或者给到主帅的压力太大了,我是觉着其实申花,现在真的是包括那天就说现场的情况也是大家都不是那么的兴奋,队员们背负的很大的压力。
+我就觉得我要迟到,依然是就是眼神当中,我都看得到就是其实有一些怎么说呢,就是那种是别人完全没有办法能够替代它,别,人也没有办法,完全能够帮他宽慰他,或者帮他把那包袱卸下来的可能性只能靠他一步一步去走,所以比赛结束以后就是大家握手,这一瞬间真的是会
+觉着,其实什么也不用再说了,但是这种感觉就是马上会好一些,那么当然他那天也在赛后,我们简单聊两句,祝他也说其实你看到吗,4支征战亚冠的球队疲态都在慢慢的展现出来,能上岗其实因为也迎来了就是大家一直不知道的这个时间,大家终于揭开谜底,只到了
+是在压在身上吗,那你说他是真的能量值战胜不了对手吗,你换个好的其他的任何一个时间,你都不用说,就是现在这个时候,你就我们都在往前一周可能状态都能比这周还好一点,但其实是我们从打客场河南那场开始我们就在说好像是更加早一点
+就是我们中场打重庆,实际就感觉好像已经有,那么一点点小状况的,所以这个就一步一步累积下来的相应的来说,申花真不容易咬牙挺过这一场之后,我觉得日子就好过一点希望,大家把能够在
+广州这场比赛能够再顺利一点,也希望吧,就是完全是因为此前这个足协杯拖累一下福利,然后让古力也疲劳一点,大家都扯扯平然后呢,也希望这两天的备战申花能够更加有效的去针对对手,其实吴指导也是非常非常擅长研究。
+对手的主帅,但可能之前因为真的经历上,可能心理上我觉得可能有些受到一些影响,那么可能也会有封神的地方,但这周还能好一点,嗯,相信客场广州不管成绩怎样,球队应该会在一个慢慢的找回自己状态的过程中。
+呃,刚才跟想要再聊,其实世界杯这个间隙到来之前,对于申花来说的只有联赛的任务,其实算福利这场有三场比赛,对阵富力是客场主场是打重庆和还有一场比赛520这一天呢,是客场打权健其实只要对赛程应该说非常了解了,那这三个比赛呢相对来说对于申花来说比较重要,因为其实在进行,且其
+到来之前,球队打这三场比赛,等于还要修差不多,将近两个月的时间才迎来接下来,这个比赛能从你也在期待或者在等待,是不是我们在经期过程当中啊,中期会有一个调整啊,到目前为止可能我们不知道,但从目前的积分排名来看呢,球队希望保持这样的一个势头,至少啊,尤其是现在对阵广州富力,你甚至
+包括对人种思维,从目前的积分排名来看,都是落后于申花儿的,所以可能很多球迷也希望吧,能把我这样的一个机会,甚至可能很多球迷也坦言,也只演到目前为止,我们只有联赛的这个任务,是不住于生活来说在心态把握方面更加纯粹一些,或者集中力和活力更加的专注一些,这是不是对于申花可能
+同时,从另外一个角度的一种帮助
+一目前等更多这种情形一定是件好事情,因为它会全力备战一套,就哪怕就是这个,其实你就光说首发阵容,他都不用再去考虑哦,我在亚冠赛场上要怎么用外援我要在足协杯上怎么使用这些队员们要在联赛当中,所以他的这个备战或者
+说,它对正常状况下的自己主阵容之间的这个磨合,都
+会有一个足够的时间来确保,那么只要是伤病情况,完全都恢复了所有可以进入到主力阵容当中的队员,都以一个最好的身体状况,那么参与到每天的这个备战训练当中去的话,应该说先咬牙挺过这三场比赛之后那个世界杯的间歇期确实。
+会对于中超赛场上,这些球队都是有所影响的,那个时候真的可能世界杯打完回来之后,我觉得中超联赛在开打的时候,你很难说每支球队所呈现出来的状态和实力是怎样的,刚才去找需要耶,我觉得很多球迷有这样的公尺联系到这个赛季征战亚冠的4支
+球队将球与其他三支,首先我们在阵容厚度方面,其实就有些薄弱,再加之我们遭遇了如此之大的商品,炒你这上面条换成任何一对,其实都面临这样的问题,没有一次,咱们咱们说难听点儿的首发阵容,相当于人轮换阵容,对吧,其实差不多是这意思,不要没拆完四个5个李强都要考虑。
+你还得给一些人找这种,是不是能够当一块砖,放在那,用,简直就是得找万能转那种感觉,就是他可能也不太熟悉,是用那个位置,但是你就先到那位置上去顶一顶唐卡对对,所以我觉得这其实艰难程度就可想而知了,而且我觉得接下来对于球队来说,伤病问题可能现在还有,因为
+很多球迷也在急需等待着曹云定的回归,那甚至其实我们看到了几个外援,整体都会有伤在身,甚至其实很多球迷也牵扯到了么,允诺关于世界杯征战这样的一个话题,那其实从赛季之初到现在为止,嗯,所以可能之前我在分析或者在采访的过程当中,包括我可能上周节目也问道兵哥李兵其实也前
+当然了,这个申花,整个赛季这样的一个前景,其实他给出了一个感觉,还是比较看好球队去排在中场,有这样的一个位置,而且它是可以提出了一个观点,其实我觉得这点身化作了一直都不错,就是始终是我们拼别人,而不是别人拼我,尤其在我们2比2战平恒大之后回来,为什么提到了大连一方,接下来对
+对恒大或者是、贵州航空界的比赛,为什么有的时候会不一样,因为你往往逼平了一个很强大的对手,甚至有机会战胜他,那上半场踢得非常棒的前提下,这个心态的把握其实对于球迷来说很关键。
+其实我在广州是认真的,听了那一个小时节目,听了自己的,也听了兵哥的,其实对我的这个触动也很大,我就是觉得其实确实有一点就兵哥知道给这支上海申花放在一个什么样的正确的位置上去看待自己其实他说的非常冷静,客观,然后呢
+又把整个球队也好,队员的这个所应该处的这个位置,和俱乐部应该有的一个状况,球队应该有的一个目标都放在了一个很合适的位置上,一个片子真的是体现其实确实是每一场比赛的这个心态,真的是不一样的就是就是他讲可能嗯
+哪怕在夺冠之战,或者怎样说你看,如果你不是用这种听的状态去打对手的话,你可能就变成另外一个样子,所以心态真的是也是这支球队可能在困难的时候,最需要去把握住的一些东西,就是,不要失去自己这支球队可能一直以来最宝贵的这些东西。
+对那么这种情况之下,发现在看就是这三轮,大家其实也一直在说,之后会有没有什么样的引援有,没有什么样的一些动向,那么几只球队我相信变化一定是有的,包括其实990譬如吗?
+求900的一些小朋友,我这不就这样说嘛,9900的小朋友们之手就会伸上来,那么身上来由,但这也有一个问题,刚刚说完,心态真的很重要的时候,就希望所有在期待他有变化的这些朋友们都能够先把最坏的可能性
+请做足,不要上来,万一这些小朋友真的打出来以后,你又开始说了,其实不行,其实根本就没有想像那么好,人家为什么没有你想象那么好,你不想想是不是一开始你给别人定位是不对的小朋友们没有打过做这种年龄,现在马上就拖上来打这个职业联赛
+而且病情的是顶级的,还是申花这样的高,关注度高,光膏可能面临指责的,这样的一些点上的时候,有的时候放轻松一点,要看到别人现在只要先能踏上中超赛场就已经是一种成功,那么这其实对于未来的申花就是
+件好事情的话,那么心理上可能就会舒服一些,不要过于的急功近利,不要过于的想就是2018赛季,一定要怎样,怎样,那可能心里就会痛快语言,但我觉得球队不会不去寻求变化,因为也包括外援方面出现了商定的这样的一个情况,那么,如果能
+做的这种积极的一些改变的话,我相信俱乐部是会去做的,但是如果真的是遭遇了什么样的一些困难,那么最终必须可能还要承担一些,承担着这样的一个困难,向前走的话,那我相信教练组也好,俱乐部也好,都会有一个最大限度努力之后的平衡的这个
+我觉着也不要担心这两天,我一直在看是有一些朋友说,在周六聊聊这个话题吧,我觉着聊聊这个话题,你们都觉着有什么意义现行,有意义的事情就是现在这支申花队好好打比赛,最近一段时间足球好像要出一个事儿啊,现新店是的,这看下去这看下
+七真的是,而且虽说这事儿,我,他们掐指一算,2021年啊,就是可能和有些人没什么太多的关系。
+但你真的会发现,就是此前如果认为我从事了这个行业,就能获得更多的一个什么样的一个社会回报,或者说一个个例了,对哪怕除了就是其实最明确的,首先是给家庭创造的这个物质条件那么其次呢,可能这个行业这个
+工作也会带给他那么社会大众对他的一种尊重,对他的一个认知。
+那你看下来,现在好像马上就又要产生另外一个一个情况,那我也看到这两天就是好多好多聪明人都在分析这种比例就是a b c的这种合同,就是这种级别的合同,应该到底到达一个什么样的状况,也说参照一下日本联赛当年就是这
+一些这种急功近利俱乐部的这个发展过程当中,如何控制它的这个投入,那么他去做的这个合同的档次,说下来说来说去,反正就是日后想看到大牌队员,或者是以高薪,这样的方式请来大白队员的概率是在越来越
+在一个减低的过程当中。
+那中超足球可能会进入到一个理性投入节,缩开支这么一个状况当中去那么接下来可能这个联赛给予大家的这个考验,会越来越多,也别着急了,那之后可能都没有大牌外援了,那边也有些俱乐部,我亲人瞬间我就当时我做。
+现在想来有些保级俱乐部应该开心,用保级俱乐部这个本土队员的这个,这个差距不是那么明显的话,那也大牌外援也不那么明显了,这联赛就开始越来越越来越煎熬,越来越纠结了,你真的就很难说到时候2021之后,谁是保级队,谁是种
+宫观对,但前提是我们先做现在对吧,悲伤眼泪也是这样,当然开局玩笑话也看看,因为斯塔来还是不来啊,到时候你来看一看,也许三年就是正好他是这种从18赛季选它不如选自然年,他就算从18赛季中期签等大家就签到,正好签到2021,然后红酒就卖到那年,然后就
+卖完红酒就结束,因为其实此前也一直在说世界应该是他这个问题,还是最关键的取决于为什么当时大家在传说是这个鲁能的时候直接就有朋友就说这不可能是鲁能为什么最关键的是它有红酒生意红酒生意这一块谁能帮他接盘才是最重要的,他不是
+是来中超联赛,更多的啊,是在卖红酒的同时推销自己的这个红酒的同时,然后来踢球的,所以这个过程当中,他得两者都能够兼顾才行,所以那个时候就马上答案就出来了就就不是这样的,所以我觉得可能未来的一段时间呢,我们在关注求各支球队吧,整体上
+上一个发展不如先把这个目光齐齐聚焦在等于520到来之前啊,就是一上港也好,申花也好,联赛也好,亚冠也好,整体这样的一个发挥,这轮联赛呢,希望伤害两对吧,一主一客有一个好的发挥嗯,因为时间关系呢,我们这周的怀孕场到这要和各位说再见也非常感谢各位的收听我是小松,我是小由我们
+中午12点到1点,与您不见不散不见不散。
+源自北欧创与丹麦
+xperia克拉根个性珠宝品牌运用银统统与xx香蕉的前卫设计里面,再将经典工艺技术与时尚做自由搭配。
+每一个近期口的面孔,都会让,你不经意地想起属于自己的爱情,亲情与友情,像经历荣与记忆,将经验化为动力,你的个性由你创造xx jerry
+丛林一路军马投身市场,鏖战
+生活就是注释上一场。
+打卡,还有好心烦打卡,到了没中,国帮我们建好吧,朋友
+一只鸟飞累了,停在树上,却用一只脚落地,为什么呢?
+因为她打了一个很大的喷嚏
+称,有,一只脚捂着鼻子
+能不能不打喷嚏的时候用纸手帕盖住口鼻健康城市美好生活

+ 26 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本3.txt

@@ -0,0 +1,26 @@
+海康威视、汇川技术、信维通信、珀莱雅、卫宁健康、跨境通、广联达、华东医药、北方华创和森马服饰成为二季度以来机构密集调研对象。
+中美握手言欢,沪深两市集体走强。上证综指站稳3200点,并创近期新高。
+多家券商认为,震荡反弹可能是接下来市场运行的主基调。
+与此同时,A股基本面又迎来一大利好——接近七成公司中报预喜。值得关注的是,五大板块个股已被机构密集调研。
+沪指站稳3200,并创近期新高        
+周一(5月21日),上证综指收涨0.64%报3213.84点;深成指涨0.87%报10765.35;创业板指涨1.4%报1862.48点。两市成交4612.2亿元,较上交易日同期明显放量
+多家机构对下一步的A股走势乐观。
+海通证券荀玉根认为,3月22日以来市场面临的最大的不确定性因素已经消除,市场开始回归到上个震荡区间,即对应上证综指3200-3500点。再往后看,市场进一步突破第三区间,震荡中枢再次抬升,需要基本面数据支撑。
+方正证券策略观点认为,目前市场处于底部位置,将迎来较好的做多机会。毛衣战“靴子落地”,外需景气持续和全球经济复苏的不确定性降低,风险偏好将得到改善。建议用盈利能力常年稳定在较高水平的白马股做底仓,继续赚业绩的收益。增加TMT、军工、医药来进攻,5月份首选医药、银行、军工。
+国泰君安表示,继续看好5月份行情,震荡反弹可能是接下来市场运行的主基调。太平洋证券首席市场分析师季晓隽也认为,现在是正在筑底的过程,如果突发重大利好,拉出一根大阳线,令指数快速脱离先前的低位,大盘就会脱离中期底部,由熊转牛。
+近七成上市公司中报预喜 
+值得关注的是,已经有接近七成的上市公司中报预喜。
+截至5月21日,沪深两市共有1096家上市公司公布2018年中报业绩预告,其中有758家公司业绩预喜,占比达69.2%。业绩持续高增长个股吸引了主力机构的关注,其中电子、计算机、化工、机械设备和医药生物五行业是二季度机构调研最为频繁的领域。
+Wind数据显示,截止5月21日,两市共有1096家上市公司公布2018年中报业绩预告,预告类型显示,中报业绩预喜(包括略增、预增、续盈和扭亏)合计758家,占69.2%;这一比例较一季度的60.9%明显回升。
+从业绩增速角度来看,中报预告增速相比于一季报将略有下行,但整体仍然处于高位。中报业绩下行的趋势与目前市场对于全年经济偏弱的预期是相一致的,但从全年来看,业绩增速仍然能够保持在一个相对较高的水平之上。
+长江证券预计全年A股整体的业绩增速将保持在13%左右,虽然相比于2017年有较为明显的下行,但是仍处在较高水平。
+从行业特征看,758家预喜公司主要集中在化工、机械设备、医药生物、电子、电气设备和轻工制造领域,分别有94家、75家、68家、59家、47家和42家。
+个股方面,预增幅度最大的是启明星辰,公司预计2018年1-6月实现净利润1500万元至2500万元,增长幅度达9629.86%至15983.10%。而启敏星辰也是目前唯一一家净利润同比预增上限超过100倍的上市公司。
+除此之外,世荣兆业、国创高新、卓翼科技、海普瑞、华东重机、北讯集团、美年健康等7家公司增幅也均在11倍-41倍之间。
+绩优股背后机构调研活跃        
+此外,Wind通过对照个股中报盈利水平发现,对于业绩预喜的绩优股,近期机构调研也越来越频繁。在弱市震荡背景下,机构调研上市公司的关注点向业务空间、业绩增长、公司财务等方面集中,通过调研,机构期望挖掘市场中的绩优个股、确定性机会。
+Wind数据显示,截止5月21日,今年二季度两市已有572家公司迎来机构调研。
+其中海康威视、汇川技术、信维通信、珀莱雅、卫宁健康、跨境通、广联达、华东医药、北方华创和森马服饰成为二季度以来机构密集调研的对象,二季度至今,调研的机构家数累计超过百家。
+从调研频次看,比亚迪、大族激光、金风科技等29家公司机构调研次数超过5次,其中19家公司已率先披露2018年中报业绩预告情况。数据显示,这19家公司中,大族激光、金风科技、信维通信、苏宁易购、一心堂、益生股份、海鸥住工等16家公司业绩预计实现增长,占比达84.2%。
+在一心堂近期的机构调研中,机构关注的问题集中在部分区域的子公司已经开始盈利的情况、部分区域盈利的可持续性以及公司2017全年的业绩指引等。
+Wind数据进一步显示,机构调研上市公司在行业分布上较集中,电子、计算机、化工、机械设备和医药生物五行业成为机构调研的密集区域,二季度机构调研家数分别为74家、57家、55家、51家和45家,累计为282家,占比全部预喜公司总数的49.3%,几乎可以用“半壁江山”来形容。

+ 67 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本4.txt

@@ -0,0 +1,67 @@
+前段时间有群友整理了我几年来的挖坑扯淡,看了几眼吓得赶紧关掉了,这都什么鬼。扯淡能力瞬间被打到零级,不敢写也不敢发,感谢 @伯通李 的当面讨论和发在虎嗅上的简写版的示范,重写了这篇勉强敢拿出来见人)。
+4月6日,住建和国土部下发通知,要求各地房产库存过低的,要显著加快供地,库存过高的要停止供地。当时心存犹疑:“库存低的要显著加快供地”和之前“严格控制特大城市扩张”的规定,打架了,哪个会赢?
+隔天,北京就宣布未来5年新增住房150万套(现有约750万套),大概是前5年新房成交量的3倍。OK,至少短期内新规定有些效力。就像计划生育了十几年,终于出来个“单独二胎”一样,信号虽小,但意味深长。
+大气候是,最近高层屡屡强调“加快形成房地产长效机制”,正好把旧机制的框架,还有新机制的博弈可能,做一个梳理。 牵扯到土地和财政、金融货币和收入循环、央地关系和政策博弈、居民的应对,这四条交错的主线都会涉及,所以这篇文章可能会比较长,而且每一段里都有小因果小逻辑,对读者要求太高了…  
+第一部分:目前状态的由来 
+1、93年到03年打下的框架
+为了节约篇幅,把93年税改和央地关系调整作为一个起点。这之前,大多部委是没钱又没权,饿的嗷嗷叫。税改之后,财权大幅上收,结果是部委们爽了,县乡饿的嗷嗷叫。
+98年进行了房地产的市场化改革,但当年修订的《土地管理法》明文规定,土地补偿费和安置补助费的总和,不得超过前三年平均年产值的15倍,省级政府批准可以增到不超过30倍。第63条又规定,“农民集体所有的土地的使用权不得出让、转让或者出租用于非农业建设”。
+这就基本把土地的口子给垄断了。极度缺钱的地方政府,在随后的史上最宏大的城市化、开发区的进程中,走上了土地财政之路,住宅用地换土地出让金,工业用地换增值税,城投平台搞基建贷款,搞的越超前升的越快。
+早期钱少事儿多,多数基层只能不讲规矩了,少不得各种因为征地拆迁而酿成的冲突和悲剧,与农业税(06年取消)、计生(16年接近取消)可以相提并论。“每一个人的家乡都在沦陷”。只剩中心城市、省会和个别城市等能在治安、教育、卫生、医疗、发展机会方面还有可观之处。这与美日欧等发达国家形成了明显对照,后者通常只有机会上的差别,小城市和乡郊的秩序,往往比大城市中心还要好。
+农村土地不准入市,资本和富豪不能下乡落地、土地不能自由交易、转变用途和获得信贷,结果是几亿农民过度依靠出售体力,勉强糊口,支付教育、医疗、进城门槛之外,没有什么消费能力,还有承担信贷的凭借。 2016年,城镇居民(约占54%)的人均可支配收入是农村的2.72倍;13亿国民中收入最低的60%,平均起来每月可支配收入仅1100元。这有多少能买的起高铁票或者进口货、三四线房产(以及钢铁水泥煤炭家电汽车)、用的起集中供热不烧小煤炉、不乱排垃圾和污水?所以“产能过剩”“环保难题”“资产泡沫”“顺差过多”等等其实是伪问题,是产权和信贷局限在城市的诸多后果而已。
+另一个后果就是,竞争中胜出的居民,极难在乡郊置办庄园、别墅、参与学区,只能继续打下一个关卡:在海外购置别墅、培育后代。附带结果之一是数以万亿计的财富成为别国公民的“海外”资产。这种财税和土地机制,近乎成为一个逐层向上、向海外抽取精英和财富的水泵矩阵,没有反哺。
+伯通做的图,漏了凌驾所有之上的最高级种姓婆罗门伯通做的图,漏了凌驾所有之上的最高级种姓婆罗门
+看懂人最后发现了这个游戏的通关秘籍,就是借助杠杆提前在中心城市卡位,“京沪永远涨”背后的逻辑大概如此。 
+2、03年后的“宏观调控”加码
+03年是换届之年。理想状态是升级基本操作系统,把93年版本中(可能是受苏联解体的刺激而不计代价的)过强中央、过弱地方的格局,做一个平衡调整。但历史通常是反过来的:一个架构运行十年,那最有话语权的往往是这个架构下的得益者。
+结果是这10年的重点变成了“纠偏”。加上民众流行的观点之一, 是教育医疗等市场化、国企私有化等太快了,需要慢下来等一等国家的良心。“宏观调控”时代来临,各部委相对于地方的权力空前提升,国企相对于民企也获得了空前的优势和资源。
+土地管制也在这期间开始层层加码,04年房地产首轮调控启动,06年出台了“18亿亩耕地红线”,结果就是大家熟悉的中心城市的房价开始超速上涨,而三四线城市库存压力更大,引发更多的部委调控。 、
+到09年应对危机时, 最初设想中其实是加杠杆和减税两个方案并行的,但由于前几年没做多少改革准备,结果变成了大放贷。到了还贷周期,民企一地鸡毛,而国企和地方基建的债务,反而为了保GDP和就业,不得不继续放下去。先是灌饱了稀缺资产的价格,接着就开始构成资金外流的压力。
+最后一步,就是13年部委按照惯性继续出台调控政策,“严厉控制特大城市扩张”,到地方开始落实(2015、2016年中心城市供地急剧减少),结果是房价恐慌性暴涨,终于触到了其他部委(央行)的线了。
+北京14年尤其是16年的供地数量是可怕的北京14年后尤其是16年的供地数量是可怕
+在撞线之前,疑似财政和央行对土地和发展规划无权吱声 – 即使他们预见到了风险也只能忍着,只有到风险临近的时候,才有可能委婉的提出:喂,这样子下去会崩掉的啊。
+插入一个可能的特色规律:
+每个部委的规定和政策都是永远正确的,如果加上了“中央精神”、“基本国策”的背书,就不仅是永远正确,还要年年加码。除非撞到了另一个部委(或者另一个国家)的红线。
+比如计生政策就长期正确,直到负责养老金的部委摔了电脑:这预算没法做了。至于民间和学者们多少声讨反对,在政策博弈中更接近于背景噪音。
+所以未来到底是按照已有模式继续下去,还是会另起套路,就要关注财政和货币当局的想法和改革准备了。 
+第二部分:多数人忽略掉的改革准备
+1、  财政部门的调整和设计
+13年起,财政部门的首次被定位为“国家治理的基础和重要支柱”,不再是出纳了,但离正常国家还有一些距离:西方财长的权力和地位,大多仅次于总统/首相,平级于国防、外交、安全、贸易等重要部长。没权力就推进缓慢,未来是会加速推进,还是人走茶凉,也不大好说。
+这几年来财政部门做了不少准备,包括:
+1)  逐步规范各部委的自由财权,要求各种专项拨款,从“跑部钱进”的抽屉里,拿到地方预算大帐的台面上来;
+2)  统一流转税(营改增),微调中央和地方的分享比例(16年底增值税定额返还);
+3)  推动地方财政的公开化和地方债券的市场化。逐步卡死地方政府从银行直接间接搞钱的通道,包括宣布18年起所有财政担保无效。
+4)  推动地方的财政法人主体定位。当债务利息达到财政收入的警戒线时,地方必须冻结支出、裁员、出售资产。(如果这条生效,还会打架的。地方被迫裁员时,多半不会先裁警察城管老师医生,而是先裁妇联、文联、工会、体委、日报社等。但上级妇联文联不乐意怎么办,拨钱吗?)
+5)  最重大的举措是设置了“央地分权”的指导意见(国发2016年49号文),国防、外交、国安、边境、跨省大河和交通、重大传染病、战略资源等归属中央事权,而教育、医疗、治安、规划等重要权力下放为央地共管或者地方主导。
+“央地分权”远超过了补丁的意义,而是接近新一代基本操作系统。大概能决定未来二十年是会在人均万把美元上玩V型、L型、I型,还是在2万美元左右小幅波动。如果大而化之的讲,甚至是从秦朝起到现在2000年里一直未能达成的框架稳定性。不过现在强调它疑似有些不合时宜,草草颁布了就冷藏起来,毕竟要分解部委和权力、扩充地方财政和法人主体资格,要动太多法规、制度、位子和利益了。
+2、土地制度的改革准备。
+土地方面的改革准备,目前看到的是今年完成城乡土地确权发证,全国房产信息联网,全国人大本届完成《土地管理法》修订(希望已经调任人大的黄市长能够参与),这些相当于是为后续改革提供一些可操作性、可监督性和法律依据,免得搞成王安石变法那种祸害。
+如果这次《土地管理法》和部委权限下放的比较到位,那即便两三亿人住进1亿套别墅占掉1亿亩耕地,现有19亿亩耕地变18亿亩也不影响粮食安全,但对于完善经济和货币内部循环链条、开启正常循环,意义可就非常重大了。
+如果小改小闹,拖20年再放开,那代价多半是20年内数百万人移民,数十万亿财富带往他国。 按目前国内专家和民意(保证粮食安全,节约利用土地,防止兼并,稳定第一等等),多半是稍有让步、继续顽固。
+如果财政和央行的压力非常巨大、并且起到主导作用,那也有可能压倒土地政策惯性的。 
+第三部分:正常财政中土地和房产税的角色
+目前财政收入结构中,增值税占比过高,而增值税非常接近工薪税(设备、原料、电力等成本可以抵扣,而人力成本不能抵扣)。再加上社保、公积金和所得税,造就了一个畸形的收入和消费结构。企业家和工薪阶层的收入的大头被拿走了。消费和信贷能力不足(产能过剩)、还款能力不足(资产价格也会有天花板)。
+形象一点儿说,就是单对着一条腿(实业)割肉,而不对财产征税。等实业、就业和工薪割到走不动甚至割垮了,那其实资产价格也走不动甚至会垮。
+在产业集聚时代,很多县乡其实已经无法维系制造业了。但由于地方政府对增值税的过度依赖,只能继续在土地、环保、信贷等方面不计代价进行维系。
+地方财力长期不足,部委们的KPI考核却变本加厉,那当地干部们只能进化出另一种天赋技能:向上花样讨钱(持续增加财政压力),向下花样糊弄,教育、医疗、环保、治安等等,除了政府周边之外都没法细看。
+而房产税天然是地方税。如果地方财政收入和政绩主要来自于地方税的话,那大概一届的时间,很多地方官也许会拿出当年绞尽脑汁、拼命喝酒也要招商引资的劲头,用在改善规划、环保、治安、教育、医疗等方面,像是换了个人。(所以不仅居民们担心薅羊毛反对房产税,其实老革命们更反对房产税:基层干部以后给谁打工?)
+当地方增值税增不动了、地方贷款又被卡死了、卖地也没人买的起的时候,地方只能葛优瘫,或者撒泼讨钱,不给钱那就得给政策(比如裁员或者卖国资),或者新的利益安排了。
+短期看的过渡策略,可能是老地老办法、新地新办法、各地自行决定。比如新增、翻建、扩建的请求,权利清晰一致同意且经过当地规划许可的,就给办证,允许出售、贷款,但必须补交市政建设基金(各地自行按区域划定每平米几百到几万元不等)、补交电力、排污、供热、垃圾处理等增容费,且年年缴纳房产税。这比地方政府原来垄断征地再卖的方式,收入可能更高。当然这只是猜测,详细可等京沪等地的“集体土地入市试点”的方案出来。
+按照“不撞红线不改革”的规律,这么正确的道路,除了尽快修改《土地管理法》允许以外,还需要什么压力才能推呢?这就是下一部分了。 
+第四部分:债务和货币安全的红线已经绷紧
+如果说土地制度、经济发展模式等等还和各种国情、文化等有关,大家可以吵个没完的话,那货币和债务可就算是普世的硬邦邦的,没的可选择的。
+基本税制、产权和行业准入等20年几乎不动,已经放开的领域里资本已经够多,极少还有额外收益了。但GDP增长、就业、财政的目标,迫使信贷继续增长,而且主要是支持利润和还款来源都很可疑的国企、政府基建项目。现在国企和地方政府的负债,早已超过百万亿的规模了。
+而我们知道,每一笔新增货币(信贷),在出生之时都已经注定了死期(还款条款),货币总量可以视为每笔尚未偿还的债务之和,就像人口总量是所有尚未死亡的个体之和。而投资收益率,是绝大多数经济指标的基础指标。企业收益低则自然会积累低,税收、就业、收入、还款能力、资产价格、信贷安全、币值汇率,大都会自然冻住或者变糟。
+这时仍然高速积累大量无法偿还的债务,那最严重的会毁掉货币信用(比如津巴布韦和委内瑞拉的财政)并进而毁掉社会秩序和政权存续;轻一点儿的会毁掉资产价格和银行(比如90年日本的地产贷款、07年美国的房贷)。 就以现在而言,再继续给没效益的国企和基建增加贷款,或者给居民恐慌性的高位买盘增加贷款(但未来还款能力处于高风险状态),那会继续推高资产价格,掏空银行还有外汇。
+尤其是今年美元加息、美帝减税,汹涌的人民币想要出海,那简直是把央行和外管放在火上烤。必须出手。
+常见的债务危机的解决出路,不外乎坐视贬值+通胀,或者主动紧缩+疗伤,或者债务转移(类似于QE,由财政和央行临时扛起来)。
+但对人民币而言,大幅贬值+通胀这条路其实没用,因为体量太大了,其他国家必须跟着贬值才能自保,没法贬值的(美元)就只能制裁,这既解决不了问题,还冲击全球秩序并导致反弹,一旦进入加码对抗循环了,保不住的可不只是人民币。
+紧缩呢则过于痛苦。设想一下98-99年财政的拮据、基层公务员的白条、国企的破产和下岗就能理解。比起20年前,可能要多一份房价的下跌,和金融从业人员的减薪和裁员。更关键的是,这次即便是紧缩了,之后也很难有WTO和房地产那种动力能够再度拉起腾飞了,寒风中要伫立多久?
+所以前两种方案都接近于白受罪而且耽误时间,因为根源还没有动,税制、土地、国资国债、国企和财政约束等方面,还远不是一个正常经济体。
+理论上财政和央行可以短期扛一阵儿,像其他经济体那样扛起国债、出掉国资。比如减增值税和社保,能立即改善企业利润、工薪和就业,增加新的消费和信贷,保住资产价格。赤字由国债过渡和弥补(相当于把债务从企业转为政府),再用国资出售来偿还国债。由于资产收益率的上升,外汇流出也会得到遏止。
+长期走向就只有“央地分权”+“土地自由”,经济、教育、医疗、保障、土地、规划、粮食等权力尽可能的下放地方和民间,包括土地使用权如何流转、变更用途、怎样开征房产税,都交由各地自己想办法去试。
+毕竟95%以上的国土不能贷款,财富单向汲取没有循环,那几百万亿货币堆在那2-3%的“出让土地”上,就像摞积木,神仙也摞不下去的,何况央行。
+所以说,这 20年来的惯性还能不能继续走下去,这次央行和货币的红线,是能直接促使土地、财税开始改革,还是经历几次“白受罪和耽误时间”,甚至会被厌恶改革的其他部委和决策者怼回去,还真不太好说。
+对读者而言,在决定是否按十几年调控期的赌博策略进行下注之前,不妨先观望思考一下,这个旧套路中央还玩不玩了,“房地产长效机制”什么时候能磨出来。 
+另:对于满脑袋马列政经思维的人,一听到土地自由就立刻想到“土地兼并”“社会动荡”“流离失所”的读者,不想回复。之前有一篇帖子猜测东亚土改等对社会生态、生育率低下的关联,可见:https://xueqiu.com/2554781328/80741990  可以参考。
+最后还得感谢伯通,要不这篇不知会在电脑里锁多久。

+ 21 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本5.txt

@@ -0,0 +1,21 @@
+我之所以打算写这篇文章,是因为昨天有个粉丝艾特了我。这个状态相信今天很多人都看到了——一个幸存的白银案女工,还有在窗外笑的变态。我相信在白银案告破后,很多人越搜索资料越发现案件的恶劣,一种害怕的感觉也就油然而生。所以,我也打算写一篇文章仔细说说关于如何面对连环杀手的问题。同样,这篇也不算是防务文。
+首先我想先给大家提前说明一件很重要的事情:防范连环杀手这不是说学学几个技巧就可以的,更不是看了这篇文章就能提升什么对于杀手的发现力。一些实际的针对性办法我会在文章最末尾提出,但是我不希望有任何人跳过之前的内容——因为必须要做好之前的了解,后面的办法才能更好运用。
+如果想要知道如何防范,那么就必须从了解“连环杀手”的定义和分类开始说起。前段文章叙述的知识会比较多,但也请认真看下去,因为前段的知识对认识一个连环杀手的性格、行为模式来讲特别重要。知己知彼,才能百战不殆。
+连环杀手这个称谓如果严格来讲,并不明确。这类人之前有一个相对应的英文名词——STRANGERKILLERS,国内暂时没有统一的翻译。我把这个翻译为陌路杀手。它强调的是犯罪者与被害人之间不认识,不存在冲突,但犯罪者连续随机挑选素不相识的人作为犯罪对象。然而后来这个概念却出现了问题,因为随着一些案件告破,各国都发现:很多杀手对杀熟人具有同样的兴趣。因而演变到现在变成了另外一个名词叫做SERIALKILLERS——也就是我们普遍意义理解的连环杀手。
+“连环杀人案”最早的定义,是在1998年美国《保护儿童免受性犯罪者侵害法案》首次提出的。当时的定义是:即由同一人犯下的一系列杀人行为,受害者超过3人,并拥有相同的作案手法和特征。明显这种定义放到现如今的情况来说是根本不够用的。
+在连环杀手频出的美国,FBI对于连环杀手的经验是公认最为丰富的,目前,FBI行为分析中心(BehavioralAnalysisUnit)以及国家犯罪分析中心(NAVAC)对于连环谋杀(SerialMurder)的定义如下:一名或多名凶手;2名或多名受害者;每起案件都在不同的地点、不同的时间发生;案件发生之间有一定的时间间隔。
+↑↑↑↑↑看到这里的我问,你们看懂FBI在定义里说的是什么话了吗?说的就是废话,讲了和没讲一样。一点清晰定义都没有,把所有可能性都涵盖进去了。时间地点遇害人数完全没有任何限制。
+是的没错——对于这类杀手的准确定义其实就是:没有。全世界没有一个大家普遍认可的定义,因为这类杀手挑选的目标、杀人的目的、手法,都有太大的不确定性。目的或是图财,或是图乐;杀人的手法多种多样;而间隔时间更不确定了。从几天到几个月不等,最长的甚至能达到20年。
+而这时候一个很重要的问题就来了——怎么分辨一个人是否是连环杀手?
+目前国际上针对连环杀手共有特性的理论不少,比如被认为是连环杀手中频发的麦克唐纳三症状:年幼时喜欢纵火、尿床、虐待动物。
+又比如近代犯罪学之父,塞萨雷·龙布罗梭的天生犯罪人理论。以及继承这套理论并将其发扬光大的一句关于犯罪心理学的名言——Geneticsloadthegun,psychologyaimsthetarget,andenvironmentpullsthetrigger。(基因给犯罪上膛,性格负责瞄准,环境扣下扳机。)
+可是上面这些个理论最大的问题在于,它们都是基于人类学早期研究中的体质人类学理论——觉得人类某种内在特征与外在生理特征有直接关联,从而从内部推断到群体体质特征及其形成和发展规律的一门科学。这一类学派在二战后被认为是纳粹种族理论的依据之一,基本没人再敢支持了。
+我在这里穿插一个名词:无情型人格障碍。有这种障碍特征的人清楚地知道什么是对什么是错,但是在感情和行为上从不因为对错来决定。我提到这个概念是因为,大约20%到50%的刑事犯罪者是无情型人格障碍;而几乎100%的侵入性连环杀人犯都是无情型人格障碍。因为这类人很难受感情牵动,因而在行事的时候极少估计后果。有趣的是在一份国外调查中,一些企业高管、金融从业者、集团高层所占的比例也不少。当然这里就做知识穿插,不发表看法。
+那么在难以分辨成因的时候,对于连环杀手的划分就显得尤为重要了。正是因为连环杀手的成因缺乏一个普遍认同的规律,所以知道他们分为哪几类,对于如何“避免”或是“识别”就尤为重要。目前来说,主流的划分方式有3种:FBI的划分方式;基于地理的划分方式;以及梅泽·塔菲特的划分方式
+先说说FBI。在这我给大家打一个预防针那就是,别看各种电视剧和电影里FBI是怎么叱咤风云的,其实FBI虽有过人之处但绝对没有影视作品里的那么夸张,特别是对于连环杀人案来说。提到FBI很多人都会想到一个名词叫“心理侧写”,而心理侧写的误差其实很大。心理侧写和犯罪肖像的成功率并不是那么高,只是一个判断罪犯的辅助,并不是小说电影里的神探一样,做一些推测就能板上钉钉的确定罪犯容貌与性格。电视剧是电视剧,现实是现实。
+FBI划分连环杀手的评判标准是杀手的行为。分类如下——
+一、猎食者:在接触被害人时立刻展开攻击行为,这种连环杀手往往都具备非常强烈的反社会人格,侵略性极强,而且作案经常是无计划性的。
+二、潜行者:亦称刺客人格型连环杀手,这种类型的连环杀手会在选定侵害目标后对其进行跟踪并尽量逐渐接近,一但出现合适的时机,就会迅速展开攻击。比如开膛手杰克。
+三、伏击者:在其控制的场所范围内实施攻击行为,侵害目标往往是身边的人或被诱骗至其控制场所内的人,这种类型的连环杀手计划性强,行事缜密,经常在相同的地点藏匿、销毁被害人尸体。
+四、遥控者:比较特殊的一种类型,通常指炸弹客或者投毒者,手法和选择遇害者的时候随机性极强。
+而基于地理的划分方式,顾名思义,评判标准便是案发的地理方位。

+ 123 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本6.txt

@@ -0,0 +1,123 @@
+​​凤凰新闻客户端主笔唐驳虎
+这组文章来晚了,不过还没有迟到。
+从上周一美国时间上午北京时间晚上,美国商务部宣布制裁中兴到现在,中兴危局已经持续超过一周。
+在当下的互联网里,一般的社会热点很少能持续超过5天,但大家都知道,“中兴事件”远远超出了一家公司的范畴,被视为对中国高端产业,甚至是对中国的严峻考验。
+过去一周,我们看到了各种各样的报道、观点和视角。大家作为中国人的爱国情怀是值得肯定的,但芯片这件事,远远超出了普通人的认知与想象。
+各种闻风而来的自媒体,立刻批量制造大批文章,很多文章情绪激动,感叹号很多,但能感觉因为缺乏事实支撑,内心底气并不足,空气中弥漫着焦躁与不安的气息。
+尤其很多抄来传去的消息并不准确,夹杂着太多错误、以讹传讹甚至谣传。剩下的,有的在宣泄对其他行业的不满吐槽(可以理解),有的还为几个用词互相打起了嘴仗。至于一如既往鼓吹投降的那些人就不必说了。
+哪怕是比较严谨的传统媒体,也把什么AI芯片,手机芯片、超算,显示屏,代工厂,龙芯、磨料全都罗列在一起,大概就类似于同时介绍大象、老鹰、柳树、玫瑰、海带、鲸鱼。总体认知依然停留在非常混沌的层面上。
+总的来说,相当一部分文章除了增加焦虑,对我们清楚认知这件事情的性质并无用处。
+面对众声喧哗,笔者只能偶尔抬头瞧一眼,并没有功夫参与。
+因为从芯片到电子元器件产业,是一个极其庞大、细密、复杂的生态体系。知之为知之,不知为不知,是知也。
+虽然笔者先前其实也都有一个大致的了解,但最终还是需要咨询多位行业内人士,广泛全面地了解市场、技术与产业,再打通技术层面、操作层面与战略层面,真正发现诸多令人讶异、闻所未闻、与印象全然不同的事实,才能看清全部的格局。
+这些调研与梳理,都是极其耗时耗力的工作,所以结果到今天才姗姗来迟。但肯定会比你至今看到的所有文章,更完整、更透彻、更全面。
+先说一个不一样的总体概论:
+美国这次找借口要挟中兴,威逼中国,是一次极其愚蠢、蠢得冒烟的轻佻举动。
+【贸易战背景下的一次要挟】
+与以往不同,今天第一篇,我们先来讲战略格局,先讲清楚几个最根本的格局问题。
+这次“禁运”正值中美贸易战之际,当然需要在贸易战的背景下去分析美方的作为。
+而笔者上个月的几篇文章,已经结合历史经纬与现实对比说清楚了,所谓的贸易战,就是川普搞的一场装腔作势的表演秀。另外,这事得拖上一阵,急不了。
+不知道有人看过《做生意的艺术》么?在书中,川普总结了自己谈判和做生意的手段。
+他擅长虚张声势,喜欢进行压迫,挑战对手的神经,借此获得谈判筹码,或者摸清对方的底牌。当然,他也喜欢和信任一贯诚信的合作伙伴。
+当然,欲加之罪何患无辞,本来就是执行上的小瑕疵,美国商务部找借口要收拾中兴,就是想以此作为谈判的又一筹码。
+不要忘了,主打贸易战的是美国商务部,“制裁”中兴的也是美国商务部。
+所以,这是在双方隔着桌子叫阵(谁也当不得真)的时候,美国突然拍了一下桌子,打算吓唬中国一下。
+但是美国算计失误了。在这种敏感时刻对中兴出手,的确严重挑衅了中国公众的神经,也一下激起了中国人的重大危机意识。
+【中国为什么有巨大的“芯片逆差”】
+拜近期密集的媒体宣传,广大公众都知道了,中国每年进口芯片2000多亿美元,比石油还多,令人感觉这么个大国至今依然很落后、很耻辱、很丢人,几乎是要羞愧得无地自容。
+可绝少有人去讲清楚背后的原因。
+2017年,中国生产了14亿部智能手机、5亿部功能手机。全世界的手机几乎都在中国生产,其中三星+苹果共5.3亿部,剩下的绝大部分都是中国品牌。
+在全球14.6亿部的智能手机出货量中,中国人购买了4.6亿部,其余10亿部智能机则销售到世界各地。现在,全世界的智能手机已经成了一年能卖4787 亿美元的大生意,在制造业里仅次于汽车。
+另外,中国还生产了1.72亿台笔记本,8600万台平板电脑,4800万台台式机,1.6亿台液晶电视。全世界的消费信息产品、黑色家电、白色家电,绝大部分都在中国生产。
+中国的电子及信息产品出口总额8200亿美元,折合5.2万亿人民币,占到中国15.3万亿元货物总出口的三分之一,也占到中国82万亿GDP的6.3%。
+这也就是为什么中国在全球的“高新技术产品”贸易中占到如此分量的原因。
+【近乎唯一的卖家与近乎唯一的买家】
+作为全球的电子整机制造基地,中国自然也是全球最大,或者说近乎唯一的集成电路(即芯片)需求市场。
+为生产这些电子设备,2017年进口集成电路2600亿美元/3770亿块,分别年增14.6%和10.1%,占大陆进口总额的14.1%,平均进口单价每个为0.69美元(约4.35元人民币)。整体规模更是1600亿美元进口原油的1.6倍以上。
+2017 年,全球半导体总销售额4122亿美元,同比增长20.6%。其中集成电路为3402亿美元。
+也就是说,中国进口了全球76%的芯片!而剩下的全球24%,也就是约800亿美元,是在中国生产的,具体是5411.3亿元人民币。
+按这些数字,全世界公开贸易的芯片,几乎都要来中国走上一遭。深圳的华强北,是全球集成电路和电子元器件的交易中心。“华强北指数”,也被世界电子供应链所紧密关注。
+当然,以上几个数字统计口径不同,也略有差异和出入参差。但总体上的确反应了中国电子制造业在全球唯一的枢纽中心地位。
+另外,这些芯片并不都全为中国整机制造业所用,包含了转口贸易与中国造芯片的直接出口等因素。2017年有近670亿美元芯片从中国出口到其他国家,占全球份额的19.6%。
+这就是为什么中国有巨大的芯片进口?
+因为中国已经把下游的电子整机产业几乎全吞食进肚了,并因此成了全球上游芯片产业80%份额的买家。中国厂商不买这些芯片,谁买?
+在全世界其他国家,尤其是曾经创造和主导了这些产业的发达国家看来,这是一件很恐怖的事情。
+【中国与美国究竟是什么关系】
+在4122亿美元的全球半导体总销售额中,美国半导体企业占了1890亿美元,在全球占比高达46%;而在占全球八成,总销售额3400亿美元的中国市场,美国企业的市场占有率达到51%。
+毕竟,美国是半导体与集成电路的开创国,这个产业至今仍是美国保持优势地位的核心领域,也是美国最重要的产业支柱之一。
+但在今天,已经没有一家公司,没有一个国家,能够单独拥有完全的ICT产业链条(Information、Communications、Technology的缩写,即信息-通信技术)。
+中国没有,美国更没有。
+所以,两个国家都深度整合在全球产业链中,美国的IC上游行业,与中国的电子整机产业,实际上是紧密绑定,一荣共荣的状态。
+因此,即使美国政府要求美国公司停止向中国出售所有芯片,产业链的所有环节都会损失严重。美国也会损失大量下游市场,自己濒临破产倒闭。
+原来的中国,其实是接受这样的全球化技术-市场布局的,可以以市场化的价格,放心地使用那些来自美国的技术元器件和架构,从而快速建立起自己的电子整机行业。
+中国作为世界第一制造大国,和已经消亡了的苏联以及经互会体系全然不同,深深融入全球贸易体系,最终在这个体系中,以惊人的速度飞速壮大。
+在家电和消费电子领域,打造出了海尔、格力、美的,华为、中兴、小米,OPPO,Vivo、联想等一批世界级的电子品牌公司。最终统治和垄断了下游整机行业。
+【下游产业做苦力,很丢人?呸!】.
+当然,根据“两个凡是”——凡是中国造不出的,都是高科技;凡是中国会造的,都是白菜价。但凡是有关中国电子整机行业成就的新闻,下面的评论一定会有人说:
+某某核心零部件是进口的,价值和利润都被外国人赚走了,国产手机只是组装货,没技术,只赚到可怜的几美元组装费。
+呸!
+还有些自以为爱国情怀的人,则怒斥这种模式是“殖民经济产业分工”,说中国沦为全球经济的组装车间。
+呸!
+这些巴普洛夫式贬低中国制造的人,已经形成了一套看似很自洽的逻辑体系:
+“外国不是技术上造不出来,而是主动放弃了低端的家电和电子终端产品”。
+“主动放弃的原因是因为利润低,不屑于做,所以进行产业转移给中国做”。
+“中国制造位于全球价值链最低端,都是组装货;外国掌握的都是核心零部件,具备高得多的价值”。
+那么我们就来用前面的宏观数据算一下最简单的账。
+中国的电子及信息产品出口总额8200亿美元,内销部分大约还有三分之一,加起来至少是1.1万亿美元。
+那么为什么只进口了2600亿美元的集成电路?再加上500亿美元显示屏?
+是国外这3000多亿美元零部件行业的价值和增值大,还是中国电子整机行业实现的8000亿美元增值大?
+中国电子整机行业为了实现这些增值,需要配套的国产塑料、铁皮、电路板之类,成本会有多高?是不是也都还是中国厂商拿到的价值?
+这本账目,是不是很令人瞠目结舌?
+这也是很多人对中国制造的最重大误解,以为中国制造只有富士康组装代工这一个环节,完全意识不到自主品牌产品在系统设计、供应链管理、营销、终端品牌等带来的巨大价值。
+【究竟什么是低端与高端】
+产业链的上游与下游,其实并不能与价值链的高端与低端对应起来,很多时候恰恰还是反的!
+可以直接告诉大家一个商业上的大致规则:
+产品上做整机,工程上做整包,研制上抓总体,基本上就能拿到整个产业链上一半的价值和利润。
+这一点看上去有点不可思议,但如果是了解手机物料成本构成的电子发烧友,就很清楚这点。当然对于苹果三星,能拿到70%。
+对一个国家而言,只要是能自主制造和打造品牌,做出了能够有市场竞争力的智能手机,哪怕物料100%都是进口的,也能掌握产业链中相当一大部分价值,养活从工程师、工厂工人、物流人员,到手机专卖店销售员在内的大批国民。
+在商业竞争中,能够做系统集成设计,完成一个复杂系统,同时还要做的比竞争对手更有竞争力,最终得到市场认可,在市场上打响品牌,其实是一件高度复杂而困难的事情。
+这是考验研发、产品、制造、供应链、管理、市场、品牌、营销、渠道、物流、仓储等综合能力的总和,其中任何一个环节有短板,都会影响商业竞争力。
+熟悉手机行业的电子产品发烧友都知道,中国的手机市场竞争,完全就是一个极度激烈的“地狱模式”——或者说,中国制造的终端消费品,几乎都是这样。而且中国的相当一部分消费者,极度崇洋媚外。
+如果中资产品在中国市场上通过激烈的撕咬,取得了绝对优势,那么离全球制霸也就不远了。
+能在三四五六七八线城镇的大街门店,把国际品牌挤得没了踪影,复制到广大的亚非拉也一点问题没有。
+HUAWEI和OPPO应该大家都认识,中间的TECNO和Infinix中国人绝大部分不认识,这是闷声发大财的深圳传音,在非洲的中端和“高端”品牌,别忘了非洲有12亿人。
+在东南亚、南亚、非洲,面对OPPO、Vivo、小米还有传音、金立的产品力、营销力、地推力,无论是当地品牌还是国际品牌,都被打得只剩一脸懵圈。
+黑非洲主要6国手机市场占有率,蓝色是TECNO,土黄色是传音的低端品牌Itel,在非洲占比超过40%,国产手机海外出货的隐形冠军
+而以欧洲为中心,华为在全球高端市场,也必将复制和颠覆三星过去十几年的逆袭道路。
+现在,三星在全球的市场份额仍有21.6%,普遍地占据全球第一。但在中国市场,三星的份额已由20%跌到了——0.8%,只用了短短五年时间。
+三星手机在中国市场的节节败退,说明了国产手机品牌的全面胜利。
+以DxO榜单华为P20 Pro绝尘登顶、小米MIX 2S追平iPhone X为标志,中国消费电子品牌在技术创新、用户体验、本土服务、应用生态、营销渠道等多方面,已经全面领先于日韩欧美品牌。
+虽然这一结果目前还只局限在中国——这个全球最大手机市场上,但随着中国手机品牌大举扬帆出海,这场较量必将逐渐蔓延到全球。
+这应该是大约20年前的一份忧心忡忡的资料,摩托罗拉品牌现在收归联想,爱立信已经退出手机市场
+不要忘了,有多少曾经风光一时的欧洲日本手机品牌,已经化为过眼云烟了啊。当然对于有14亿人口的中国而言,仅仅做整机是不够的。
+在掌握了总体和品牌之后,一是力求不断提高产品和品牌的附加价值,打造出高端品牌,进军价值链高端;
+二肯定是进军产业链上游,从易到难,一步一步实现零部件的进口替代,逐渐攻克零部件市场份额,最终实现对全产业链的掌控。
+本来,这是一个逐步而渐进的过程,但是,美国的叫阵,把这个进程大幅提前了。
+【美国拍了桌子叫阵,那就怪不得中国了】
+在贸易战相关文章中,笔者就写到。美国的战术再怎么精妙,也阻挡不了战略的颓势,更掩盖不了美国种种优势禀赋的丧失。
+川普现在把矛头指向中国,这只显示出,美国已失去了该领域的霸主地位。正因为美国恼羞成怒,突然拍了一下桌子,也的确吓了一下中国人。
+但这也让中国人清晰的认识到,中国到了这个分量,不发展自主的半导体产业,那就会把咽喉留在对手面前,万一有什么摩擦,能被别人随时能掐得住,这种感觉不好。
+美国的轻佻挑衅,立刻被中国人警惕的意识到了冷战级别的国家经济安全、科技安全、信息安全危机。
+这个事件逼迫、敦促、鞭策中国,要用最短的时间,把上游的整个芯片产业也全吞进肚,一点不剩。
+一万亿美元以上的整机产值,我们要!3000亿美元的零件产值,我们也要!
+最基本的目标,至少是建立起一条完全不依赖于国外也就是整个西方体系(美日韩台欧)的全自主ICT产业链。这就是现在中国公众的期待与要求。
+这就是要动所有发达国家的奶酪了。
+因此,美国这次轻佻的挑衅,唯一的后果就是促使中国更加强力和坚决地投资IC产业,更快的提速中国的进步,更早地削弱美国的优势。
+除此之外,美国得不到什么好处。而这个事件,应该是能够记录在世界史和人类史上的。
+从现在开始,新的时间开启了。
+【征途不在远方,就在脚下】
+有人担心,“中兴禁运”事件的爆发,一方面打破了一些人对于“中国已经天下无敌”的狂躁认识,另一方面又有可能使人们重新掉入“中国制造依然低端落后”的认知旧怪圈。
+的确,这些年,动不动就是日式中二的“征途星辰大海”,或者小资情怀的“奔向诗与远方”。说实话,笔者个人并不喜欢这种过于夸张轻佻的表达。
+笔者还是喜欢纯中国味道的“敢问路在何方?路在脚下”,有脚踏实地的精神,有乐观豪迈的壮志,更有一种举重若轻的态度。中国人,还是按照中国人的步伐前进吧。
+至于那些永远在指责嘲笑中国这也不行那也不行的,自恨自怨的一族,那自然是有的。唧唧歪歪、鹦鹉学舌,这些话语,自“贸易战”以来,已经见很多了。
+就懒得与这些人掰扯了,直接抄录69年前那份著名的演讲,做一个最后的回应吧,全般适用的大实话还真挺多的:
+我们有一个共同的感觉,这就是我们的工作将写在人类的历史上,它将表明:占人类总数四分之一的中国人从此站立起来了。
+我们面前的困难是有的,而且是很多的,但是我们确信:一切困难都将被全国人民的英勇奋斗所战胜。中国人民已经具有战胜困难的极其丰富的经验。
+如果我们的先人和我们自己能够渡过长期的极端艰难的岁月,战胜了强大的内外反动派,为什么不能在胜利以后建设一个繁荣昌盛的国家呢?
+只要我们仍然保持艰苦奋斗的作风,只要我们团结一致,只要我们坚持人民民主专政和团结国际友人,我们就能在经济战线上迅速地获得胜利。
+让那些内外反动派在我们面前发抖罢! 让他们去说我们这也不行那也不行罢!中国人民的不屈不挠的努力,必将稳步地达到自己的目的!
+又有人说了,你这不也在空喊口号么?中国芯片到底怎么样,竟然连一个字都还没提
+别急啊,下一篇开始,我们不喊口号,不谈情怀,认认真真地梳理战役层面,究竟是怎样的盘面格局,真打起来,又会怎样。不妄自尊大,也不妄自菲薄,审慎地对待一切。
+我们要一一细数,摆在前面的目标,究竟什么是比较容易的事,什么是相当困难的事,什么是难得上天但也要做的事;还有什么是无人提及、少人知晓,甚至政府投资导向也都完全忽略,却又极为重要的事。
+现在只是一个开篇,讲的是总体格局,别急啊,别急。
+凤凰新闻客户端主笔唐驳虎​​​​

+ 45 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/data/testCase/文本7.txt

@@ -0,0 +1,45 @@
+没人会否认,平井一夫就是是索粉与索尼相互养成的偶像。
+成都魅力赏现场,索尼新一波创纪录的业绩预期每公布一个数字,在场的粉丝总会“Wow”一声。这声“Wow”在一个人出现时到达了最大声。并不难猜,这个人就是平井一夫。
+实际上,从这个月一日起,平井一夫就不再担任索尼的总裁兼 CEO。他的新职位是退居幕后的索尼董事长。尽管如此,不管他是何种身份,也无论是粉丝之夜还是魅力赏,哪怕就是场外的体验展台,只要平井一夫现身,现场立马就会响起日语的、英语的、中文的叫喊声,躁动和哭腔。
+整个场面并不比逊色大牌明星见面会。
+一个日本企业家为什么在中国会获得如此高的知名度和号召力?套用到目前流行的明星养成选秀,这似乎也不难理解。
+时间退回六年前,那时的索尼正处于风雨飘摇的末路时期。产品创新的乏力、资本市场的背弃,“破产”并非只是一句简单的调侃。
+2012 年 4 月 1 日,平井一夫正式出任索尼公司 CEO 兼总裁。这时,PS 业务出身的他对于游戏铁粉之外的大多数索尼粉丝而言,只是一个素人。
+他在任内推行的“One Sony 政策”和“中期计划”则是一场旷日持久的养成直播。
+尽管难说尽善尽美,但在他的治下,一方面,索尼各个业务开始了产品线的精简;另一方面,在平井一夫的关照下,索尼成立了一个名为为 Future Lab (未来实验室)的创意研发项目。这项目的主要目的是向公众公开某些产品的原型,通过收集公众的想法意见来规划产品的发展方向。简单地说,该项目旨在让索尼那些黑科技原型机更能符合公众需求。
+如此之下,索尼开始焕发新的生机。到平井一夫改革初见成效的 2015 财年,按通用会计准则计,索尼在这一财年共实现了 81057 亿日元(717.32 亿美元)的营收,营业利润为 2942 亿日元(约合 26.04 亿美元),净利润为 1478 亿日元(约合 13.08 亿美元),而此前一年,索尼净利润为-1260 亿日元。
+在平井一夫即将离任的消息前后,索尼发布了 2017 财年 Q3 财报:销售额增长 11.5%,为 26723 亿日元。营业利润大涨 279.8%,达 3508 亿日元。所有业务(作者注:包括移动业务)均实现盈利,索尼 2017 财年前三季度累计盈利已达 7127 亿日元。并且,索尼在财报中将本财年营业利润预期再次提高,至 7200 亿日元。不出意外,索尼的利润在 2017 财年将创下 72 年历史的新高。
+索粉们也从此放心——有平井一夫在,索尼说什么也不可能破产。
+一个企业家偶像就此养成。
+在索粉们心目中,平井一夫早已是超越一般 CEO 的存在。粉丝们一方面做着有关于他的表情包,调侃地追问“索尼今天破产了吗?”,另一方面,在他发布会上的“Wow”和“Kando(感动)”感召下,心甘情愿地献上膝盖和钱包,借着平井一夫(的表情包),粉丝和索尼保持着一种微妙的平衡。
+如果说以上都是索粉们的自发行为,那么这场成都举行的索粉之夜上,索尼官方安排的节目《川剧变脸》中,演员最后一刻将脸变成“姨夫的微笑”便大有“官方逼死同人”之感。
+看到这样严肃认真又带头恶搞的索尼,铁粉的钱包基本是保不住了。
+而一个会沙画的索粉在画出平井一夫怀抱熊猫的画面并呈现在大屏幕上,而“姨夫”在一旁魔性微笑,是这场索粉之夜最让人动容的时刻,因为没有人知道这是不是这个力挽索尼于破产边缘的男人亲自参加的最后一场索粉之夜了。
+对于索粉而言,他们一年之内最重要的节日是 Sony Expo
+当然,这个活动还有一个简洁好记又十分贴切的名字——索尼魅力赏。从 2014 年开始,到 2017 年,这个活动先后在上海、北京、广州举办。
+于索尼而言,魅力赏是索尼中国、索尼移动、索尼互娱、索尼音乐、索尼影视等索尼在华企业看家本领和顶级“黑科技”的大汇演,是对之前财年的完整总结,也是对崭新一年的美好展望。
+2018 年 4 月 12 日,成都接过上海、北京、广州的衣钵,成为这些索尼在华企业的最新汇演舞台。
+而对于索尼的中国铁杆粉丝们来说,魅力赏则意味着一场庆典。某种意义上,因为魅力赏开幕当晚的“索粉之夜”的存在,魅力赏又不止于节日。它成为了索粉们一个“绝对立场”被打开与志同道合的伙伴合作补完的过程,是一次索粉们对于人生方向的自我审视。
+索尼魅力赏,还是索粉们的一场朝圣。
+既然是朝圣,这就意味着其门槛是不低的。虽不至于“三步一跪、九步一叩”,但魅力赏,尤其是参加索粉之夜的几十个索粉们都是从全国成千上万的报名索粉中选出来的。说这群粉丝是精挑细选出来的坚定信仰者,并不为过。
+让索粉们扬眉吐气的魅力赏,从索尼的业绩猛涨开始
+从 2003 年 4 月已经成为专有名词的“索尼震撼(Sony Shock)”起,索尼的多项业务、乃至整个公司都陷入了低迷状态。
+哪怕经过斯金格可以称为“巨变”的改革,从 2008 财年到 2014 财年,除 2012 财年外,索尼每一个财年都在亏损,其背后的原因与索尼在和韩国竞争对手的争夺中,为了市场占有率和营收而放弃利润有关,当然也和大地震等天灾有关。而 2012 财年的盈利则是因为索尼在当年出售了大楼等资产。
+和如今日渐成为产业的“偶像饭圈”逻辑相似,当偶像的事业进入低谷,摇摆的粉丝会脱粉,坚定的铁粉会憋着一口气进行更大力度的应(花)援(钱)。
+几十年持续的高质量消费电子品产出,和最近十年因为产品之外的因素而被看衰,这种独特的经历让索尼积累一批数量庞大又舍得花钱的铁粉。嗯,无论是对于品牌的深刻理解还是购买力,那些新晋的国产手机品牌粉丝比起索粉,只能算是后辈。
+整个行业忠诚度和购买力能与索粉相对比的是苹果的果粉。当两者又有极大的不同,至少,憋着一口气的索粉总是勇于一边自黑、一边应援。这个圈子里的知名博主“今天 SONY 破产了吗 ”,看似戏谑的背后,其实质是一个一直用着索尼手机的粉丝。
+话又说回去,即使每天都在进行“破产没有?”的灵魂拷问,索粉们最乐于见到的依然是索尼恢复往日荣耀。
+足以让这些粉丝们扬眉吐气的是,索尼在本次魅力赏上带来了业绩和产品的好消息。
+索尼中国总裁高桥洋在活动的一开始就公布:
+集团全年有望创造 7200 亿日元营业利润的历史最佳业绩。此外,仅在 2017 年上半年,索尼在中国市场的业绩同比增长超过 30%。
+从由电视、数码影像、音频组成的消费电子业务,到 PlayStation 业务,再到索尼音乐等业务都可以说在各自领域取得了优势。
+这里再说几个数字。
+索尼电视在 2017 年 OLED 彩电市场的销售份额(金额)为 34%,排名第一、“65 英寸及以上市场份额(金额)排名第一”、“一万元人民币以上彩电市场份额(数量)排名第一”。
+索尼游戏业务正式回归中国三年,共计发行了 150 多款游戏作品。截止 2017 年 12 月 31 日,PS4 全球销量超过 7360 万台,游戏作品软件销量为 6 亿 4500 万张,PlayStation Plus 会员突破 3150 万人。PS VR 全球销量达到 200 万台,出现了超过 150 款精品 PS VR 游戏,全球 PS VR 游戏销量超过 1220 万张。
+世界上 TOP 6 的智能手机公司均是索尼影像传感器的客户。在介绍这一部分时,高桥洋还曝出了金句,“现在用索尼手机的人不多,但不用索尼传感器的手机很少”。索尼移动不姓索,算是官宣了(手动斜眼)。
+如果说,这些数字太抽象的话,一个更具象的变化在说明索尼的财政状况确实在不断向好:相比去前年魅力赏逼仄的场地,今年,整个成都可谓都被索尼承包。从春熙路到来福士广场,这些成都的商业地标都充满了索尼的印记。
+后记
+不出意外,一份创造索尼历史新高的财报将在一个月之后正式发布,而它的分量索尼和索粉都明白。
+厂家拿出优秀的产品,消费者实打实地花钱去购买。
+什么叫“你只管认真,我们帮你赢”?
+这就叫。

+ 10 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/example.py

@@ -0,0 +1,10 @@
+from rakeUtil.Rake import Rake
+
+obj = Rake()
+stop_path = "rakedata/stoplist/中文停用词表(1208个).txt"
+conj_path = "rakedata/stoplist/中文分隔词词库.txt"
+obj.initializeFromPath(stop_path, conj_path)
+
+path = 'rakedata/testCase/文本1.txt'
+result = obj.extractKeywordFromPath(path)
+print(result)

+ 127 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/Rake.py

@@ -0,0 +1,127 @@
+import operator
+from typing import List, Tuple, Optional
+import os
+import jieba
+import jieba.posseg as pseg
+from .word import Word
+from .utils import notNumStr
+
+class Rake:
+
+    def __init__(self): # , stopwordPath: str = None, delimWordPath: str = None):
+        # If both Found and Initialized
+        self.initialized = False
+        self.stopWordList = list()
+        self.delimWordList = list()
+
+    def initializeFromPath(self, stopwordPath: str = "", delimWordPath: str = ""):
+        if not os.path.exists(stopwordPath):
+            print("Stop Word Path invalid")
+            return
+
+        if not os.path.exists(delimWordPath):
+            print("Delim Word Path Invalid")
+            return
+
+        swLibList = [line.rstrip('\n') for line in open(stopwordPath,'r',encoding="utf-8")]
+        conjLibList = [line.rstrip('\n') for line in open("data/stoplist/中文分隔词词库.txt",'r',encoding="utf-8")]
+        self.initializeFromList(swLibList, conjLibList)
+        return
+        
+    def initializeFromList(self, swList : List = None, dwList : List = None):
+        self.stopWordList = swList
+        self.delimWordList = dwList
+        
+        if len(self.stopWordList) == 0 or len(self.delimWordList) == 0:
+            print("Empty Stop word list or deliminator word list, uninitialized")
+            return
+        else:
+            self.initialized = True
+
+    def extractKeywordFromPath(self, text : str, num_kw : int = 10):
+        if not self.initialized:
+            print("Not initialized")
+            return 
+
+        with open(text,'r',encoding="utf-8") as fp:
+            text = fp.read()
+        return self.extractKeywordFromString(text, num_kw = num_kw)
+        
+    def extractKeywordFromString(self, text : str, num_kw : int = 10):
+        rawtextList = pseg.cut(text)
+
+        # Construct List of Phrases and Preliminary textList
+        textList = []
+        listofSingleWord = dict()
+        lastWord = ''
+        poSPrty = ['m','x','uj','ul','mq','u','v','f']
+        meaningfulCount = 0
+        checklist = []
+        for eachWord, flag in rawtextList:
+            checklist.append([eachWord,flag])
+            if eachWord in self.delimWordList or not notNumStr(eachWord) or eachWord in self.stopWordList or flag in poSPrty or eachWord == '\n':
+                if lastWord != '|':
+                    textList.append("|")
+                    lastWord = "|"
+            elif eachWord not in self.stopWordList and eachWord != '\n':
+                textList.append(eachWord)
+                meaningfulCount += 1
+                if eachWord not in listofSingleWord:
+                    listofSingleWord[eachWord] = Word(eachWord)
+                lastWord = ''
+
+        # Construct List of list that has phrases as wrds
+        newList = []
+        tempList = []
+        for everyWord in textList:
+            if everyWord != '|':
+                tempList.append(everyWord)
+            else:
+                newList.append(tempList)
+                tempList = []
+
+        tempStr = ''
+        for everyWord in textList:
+            if everyWord != '|':
+                tempStr += everyWord + '|'
+            else:
+                if tempStr[:-1] not in listofSingleWord:
+                    listofSingleWord[tempStr[:-1]] = Word(tempStr[:-1])
+                    tempStr = ''
+
+        # Update the entire List
+        for everyPhrase in newList:
+            res = ''
+            for everyWord in everyPhrase:
+                listofSingleWord[everyWord].updateOccur(len(everyPhrase))
+                res += everyWord + '|'
+            phraseKey = res[:-1]
+            if phraseKey not in listofSingleWord:
+                listofSingleWord[phraseKey] = Word(phraseKey)
+            else:
+                listofSingleWord[phraseKey].updateFreq()
+
+        # Get score for entire Set
+        outputList = dict()
+        for everyPhrase in newList:
+
+            if len(everyPhrase) > 5:
+                continue
+            score = 0
+            phraseString = ''
+            outStr = ''
+            for everyWord in everyPhrase:
+                score += listofSingleWord[everyWord].returnScore()
+                phraseString += everyWord + '|'
+                outStr += everyWord
+            phraseKey = phraseString[:-1]
+            freq = listofSingleWord[phraseKey].getFreq()
+            if freq / meaningfulCount < 0.01 and freq < 3 :
+                continue
+            outputList[outStr] = score
+
+        sorted_list = sorted(outputList.items(), key = operator.itemgetter(1), reverse = True)
+        return sorted_list[:num_kw]
+
+
+        

+ 0 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/__init__.py


+ 29 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/utils.py

@@ -0,0 +1,29 @@
+import json
+
+# Check if contains num
+def notNumStr(instr):
+    for item in instr:
+        if '\u0041' <= item <= '\u005a' or ('\u0061' <= item <='\u007a') or item.isdigit():
+            return False
+    return True
+
+# Read Target Case if Json
+def readSingleTestCases(testFile):
+    with open(testFile) as json_data:
+        try:
+            testData = json.load(json_data)
+        except:
+            # This try block deals with incorrect json format that has ' instead of "
+            data = json_data.read().replace("'",'"')
+            try:
+                testData = json.loads(data)
+                # This try block deals with empty transcript file
+            except:
+                return ""
+    returnString = ""
+    for item in testData:
+        try:
+            returnString += item['text']
+        except:
+            returnString += item['statement']
+    return returnString

+ 23 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/rakeUtil/word.py

@@ -0,0 +1,23 @@
+
+# Data structure for holding data
+class Word():
+    def __init__(self, char, freq = 0, deg = 0):
+        self.freq = freq
+        self.deg = deg
+        self.char = char
+
+    def returnScore(self):
+        return self.deg/self.freq
+
+    def updateOccur(self, phraseLength):
+        self.freq += 1
+        self.deg += phraseLength
+
+    def getChar(self):
+        return self.char
+
+    def updateFreq(self):
+        self.freq += 1
+
+    def getFreq(self):
+        return self.freq

+ 2 - 0
Rake_For_Chinese-master/Rake_For_Chinese-master/requirements.txt

@@ -0,0 +1,2 @@
+numpy
+jieba

BIN
__pycache__/main.cpython-38.pyc


BIN
__pycache__/util.cpython-38.pyc


+ 405 - 0
autoSub_dev/autosub/__init__-0.4.0.py

@@ -0,0 +1,405 @@
+"""
+Defines autosub's main functionality.
+"""
+
+#!/usr/bin/env python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import argparse
+import audioop
+import json
+import math
+import multiprocessing
+import os
+import subprocess
+import sys
+import tempfile
+import wave
+
+import requests
+from googleapiclient.discovery import build
+from progressbar import ProgressBar, Percentage, Bar, ETA
+
+from autosub.constants import (
+    LANGUAGE_CODES, GOOGLE_SPEECH_API_KEY, GOOGLE_SPEECH_API_URL,
+)
+from autosub.formatters import FORMATTERS
+
+DEFAULT_SUBTITLE_FORMAT = 'srt'
+DEFAULT_CONCURRENCY = 10
+DEFAULT_SRC_LANGUAGE = 'en'
+DEFAULT_DST_LANGUAGE = 'en'
+
+
+def percentile(arr, percent):
+    """
+    Calculate the given percentile of arr.
+    """
+    arr = sorted(arr)
+    index = (len(arr) - 1) * percent
+    floor = math.floor(index)
+    ceil = math.ceil(index)
+    if floor == ceil:
+        return arr[int(index)]
+    low_value = arr[int(floor)] * (ceil - index)
+    high_value = arr[int(ceil)] * (index - floor)
+    return low_value + high_value
+
+
+class FLACConverter(object): # pylint: disable=too-few-public-methods
+    """
+    Class for converting a region of an input audio or video file into a FLAC audio file
+    """
+    def __init__(self, source_path, include_before=0.25, include_after=0.25):
+        self.source_path = source_path
+        self.include_before = include_before
+        self.include_after = include_after
+
+    def __call__(self, region):
+        try:
+            start, end = region
+            start = max(0, start - self.include_before)
+            end += self.include_after
+            temp = tempfile.NamedTemporaryFile(suffix='.flac')
+            command = ["ffmpeg", "-ss", str(start), "-t", str(end - start),
+                       "-y", "-i", self.source_path,
+                       "-loglevel", "error", temp.name]
+            use_shell = True if os.name == "nt" else False
+            subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+            return temp.read()
+
+        except KeyboardInterrupt:
+            return None
+
+
+class SpeechRecognizer(object): # pylint: disable=too-few-public-methods
+    """
+    Class for performing speech-to-text for an input FLAC file.
+    """
+    def __init__(self, language="en", rate=44100, retries=3, api_key=GOOGLE_SPEECH_API_KEY):
+        self.language = language
+        self.rate = rate
+        self.api_key = api_key
+        self.retries = retries
+
+    def __call__(self, data):
+        try:
+            for _ in range(self.retries):
+                url = GOOGLE_SPEECH_API_URL.format(lang=self.language, key=self.api_key)
+                headers = {"Content-Type": "audio/x-flac; rate=%d" % self.rate}
+
+                try:
+                    resp = requests.post(url, data=data, headers=headers)
+                except requests.exceptions.ConnectionError:
+                    continue
+
+                for line in resp.content.decode('utf-8').split("\n"):
+                    try:
+                        line = json.loads(line)
+                        line = line['result'][0]['alternative'][0]['transcript']
+                        return line[:1].upper() + line[1:]
+                    except IndexError:
+                        # no result
+                        continue
+
+        except KeyboardInterrupt:
+            return None
+
+
+class Translator(object): # pylint: disable=too-few-public-methods
+    """
+    Class for translating a sentence from a one language to another.
+    """
+    def __init__(self, language, api_key, src, dst):
+        self.language = language
+        self.api_key = api_key
+        self.service = build('translate', 'v2',
+                             developerKey=self.api_key)
+        self.src = src
+        self.dst = dst
+
+    def __call__(self, sentence):
+        try:
+            if not sentence:
+                return None
+
+            result = self.service.translations().list( # pylint: disable=no-member
+                source=self.src,
+                target=self.dst,
+                q=[sentence]
+            ).execute()
+
+            if 'translations' in result and result['translations'] and \
+                'translatedText' in result['translations'][0]:
+                return result['translations'][0]['translatedText']
+
+            return None
+
+        except KeyboardInterrupt:
+            return None
+
+
+def which(program):
+    """
+    Return the path for a given executable.
+    """
+    def is_exe(file_path):
+        """
+        Checks whether a file is executable.
+        """
+        return os.path.isfile(file_path) and os.access(file_path, os.X_OK)
+
+    fpath, _ = os.path.split(program)
+    if fpath:
+        if is_exe(program):
+            return program
+    else:
+        for path in os.environ["PATH"].split(os.pathsep):
+            path = path.strip('"')
+            exe_file = os.path.join(path, program)
+            if is_exe(exe_file):
+                return exe_file
+    return None
+
+
+def extract_audio(filename, channels=1, rate=16000):
+    """
+    Extract audio from an input file to a temporary WAV file.
+    """
+    temp = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
+    if not os.path.isfile(filename):
+        print("The given file does not exist: {}".format(filename))
+        raise Exception("Invalid filepath: {}".format(filename))
+    if not which("ffmpeg"):
+        print("ffmpeg: Executable not found on machine.")
+        raise Exception("Dependency not found: ffmpeg")
+    command = ["ffmpeg", "-y", "-i", filename,
+               "-ac", str(channels), "-ar", str(rate),
+               "-loglevel", "error", temp.name]
+    use_shell = True if os.name == "nt" else False
+    subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+    return temp.name, rate
+
+
+def find_speech_regions(filename, frame_width=4096, min_region_size=0.5, max_region_size=6): # pylint: disable=too-many-locals
+    """
+    Perform voice activity detection on a given audio file.
+    """
+    reader = wave.open(filename)
+    sample_width = reader.getsampwidth()
+    rate = reader.getframerate()
+    n_channels = reader.getnchannels()
+    chunk_duration = float(frame_width) / rate
+
+    n_chunks = int(math.ceil(reader.getnframes()*1.0 / frame_width))
+    energies = []
+
+    for _ in range(n_chunks):
+        chunk = reader.readframes(frame_width)
+        energies.append(audioop.rms(chunk, sample_width * n_channels))
+
+    threshold = percentile(energies, 0.2)
+
+    elapsed_time = 0
+
+    regions = []
+    region_start = None
+
+    for energy in energies:
+        is_silence = energy <= threshold
+        max_exceeded = region_start and elapsed_time - region_start >= max_region_size
+
+        if (max_exceeded or is_silence) and region_start:
+            if elapsed_time - region_start >= min_region_size:
+                regions.append((region_start, elapsed_time))
+                region_start = None
+
+        elif (not region_start) and (not is_silence):
+            region_start = elapsed_time
+        elapsed_time += chunk_duration
+    return regions
+
+
+def generate_subtitles( # pylint: disable=too-many-locals,too-many-arguments
+        source_path,
+        output=None,
+        concurrency=DEFAULT_CONCURRENCY,
+        src_language=DEFAULT_SRC_LANGUAGE,
+        dst_language=DEFAULT_DST_LANGUAGE,
+        subtitle_file_format=DEFAULT_SUBTITLE_FORMAT,
+        api_key=None,
+    ):
+    """
+    Given an input audio/video file, generate subtitles in the specified language and format.
+    """
+    audio_filename, audio_rate = extract_audio(source_path)
+
+    regions = find_speech_regions(audio_filename)
+
+    pool = multiprocessing.Pool(concurrency)
+    converter = FLACConverter(source_path=audio_filename)
+    recognizer = SpeechRecognizer(language=src_language, rate=audio_rate,
+                                  api_key=GOOGLE_SPEECH_API_KEY)
+
+    transcripts = []
+    if regions:
+        try:
+            widgets = ["Converting speech regions to FLAC files: ", Percentage(), ' ', Bar(), ' ',
+                       ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+            extracted_regions = []
+            for i, extracted_region in enumerate(pool.imap(converter, regions)):
+                extracted_regions.append(extracted_region)
+                pbar.update(i)
+            pbar.finish()
+
+            widgets = ["Performing speech recognition: ", Percentage(), ' ', Bar(), ' ', ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+
+            for i, transcript in enumerate(pool.imap(recognizer, extracted_regions)):
+                transcripts.append(transcript)
+                pbar.update(i)
+            pbar.finish()
+
+            if src_language.split("-")[0] != dst_language.split("-")[0]:
+                if api_key:
+                    google_translate_api_key = api_key
+                    translator = Translator(dst_language, google_translate_api_key,
+                                            dst=dst_language,
+                                            src=src_language)
+                    prompt = "Translating from {0} to {1}: ".format(src_language, dst_language)
+                    widgets = [prompt, Percentage(), ' ', Bar(), ' ', ETA()]
+                    pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+                    translated_transcripts = []
+                    for i, transcript in enumerate(pool.imap(translator, transcripts)):
+                        translated_transcripts.append(transcript)
+                        pbar.update(i)
+                    pbar.finish()
+                    transcripts = translated_transcripts
+                else:
+                    print(
+                        "Error: Subtitle translation requires specified Google Translate API key. "
+                        "See --help for further information."
+                    )
+                    return 1
+
+        except KeyboardInterrupt:
+            pbar.finish()
+            pool.terminate()
+            pool.join()
+            print("Cancelling transcription")
+            raise
+
+    timed_subtitles = [(r, t) for r, t in zip(regions, transcripts) if t]
+    formatter = FORMATTERS.get(subtitle_file_format)
+    formatted_subtitles = formatter(timed_subtitles)
+
+    dest = output
+
+    if not dest:
+        base = os.path.splitext(source_path)[0]
+        dest = "{base}.{format}".format(base=base, format=subtitle_file_format)
+
+    with open(dest, 'wb') as output_file:
+        output_file.write(formatted_subtitles.encode("utf-8"))
+
+    os.remove(audio_filename)
+
+    return dest
+
+
+def validate(args):
+    """
+    Check that the CLI arguments passed to autosub are valid.
+    """
+    if args.format not in FORMATTERS:
+        print(
+            "Subtitle format not supported. "
+            "Run with --list-formats to see all supported formats."
+        )
+        return False
+
+    if args.src_language not in LANGUAGE_CODES.keys():
+        print(
+            "Source language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if args.dst_language not in LANGUAGE_CODES.keys():
+        print(
+            "Destination language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if not args.source_path:
+        print("Error: You need to specify a source path.")
+        return False
+
+    return True
+
+
+def main():
+    """
+    Run autosub as a command-line program.
+    """
+    parser = argparse.ArgumentParser()
+    parser.add_argument('source_path', help="Path to the video or audio file to subtitle",
+                        nargs='?')
+    parser.add_argument('-C', '--concurrency', help="Number of concurrent API requests to make",
+                        type=int, default=DEFAULT_CONCURRENCY)
+    parser.add_argument('-o', '--output',
+                        help="Output path for subtitles (by default, subtitles are saved in \
+                        the same directory and name as the source path)")
+    parser.add_argument('-F', '--format', help="Destination subtitle format",
+                        default=DEFAULT_SUBTITLE_FORMAT)
+    parser.add_argument('-S', '--src-language', help="Language spoken in source file",
+                        default=DEFAULT_SRC_LANGUAGE)
+    parser.add_argument('-D', '--dst-language', help="Desired language for the subtitles",
+                        default=DEFAULT_DST_LANGUAGE)
+    parser.add_argument('-K', '--api-key',
+                        help="The Google Translate API key to be used. \
+                        (Required for subtitle translation)")
+    parser.add_argument('--list-formats', help="List all available subtitle formats",
+                        action='store_true')
+    parser.add_argument('--list-languages', help="List all available source/destination languages",
+                        action='store_true')
+
+    args = parser.parse_args()
+
+    if args.list_formats:
+        print("List of formats:")
+        for subtitle_format in FORMATTERS:
+            print("{format}".format(format=subtitle_format))
+        return 0
+
+    if args.list_languages:
+        print("List of all languages:")
+        for code, language in sorted(LANGUAGE_CODES.items()):
+            print("{code}\t{language}".format(code=code, language=language))
+        return 0
+
+    if not validate(args):
+        return 1
+
+    try:
+        subtitle_file_path = generate_subtitles(
+            source_path=args.source_path,
+            concurrency=args.concurrency,
+            src_language=args.src_language,
+            dst_language=args.dst_language,
+            api_key=args.api_key,
+            subtitle_file_format=args.format,
+            output=args.output,
+        )
+        print("Subtitles file created at {}".format(subtitle_file_path))
+    except KeyboardInterrupt:
+        return 1
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())

+ 434 - 0
autoSub_dev/autosub/__init__.py

@@ -0,0 +1,434 @@
+"""
+Defines autosub's main functionality.
+"""
+
+#!/usr/bin/env python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import argparse
+import audioop
+import math
+import multiprocessing
+import os
+from json import JSONDecodeError
+import subprocess
+import sys
+import tempfile
+import wave
+
+import json
+import requests
+try:
+    from json.decoder import JSONDecodeError
+except ImportError:
+    JSONDecodeError = ValueError
+
+from googleapiclient.discovery import build
+from progressbar import ProgressBar, Percentage, Bar, ETA
+
+from autosub.constants import (
+    LANGUAGE_CODES, GOOGLE_SPEECH_API_KEY, GOOGLE_SPEECH_API_URL,
+)
+from autosub.formatters import FORMATTERS
+
+DEFAULT_SUBTITLE_FORMAT = 'srt'
+DEFAULT_CONCURRENCY = 10
+DEFAULT_SRC_LANGUAGE = 'en'
+DEFAULT_DST_LANGUAGE = 'en'
+
+
+def percentile(arr, percent):
+    """
+    Calculate the given percentile of arr.
+    """
+    arr = sorted(arr)
+    index = (len(arr) - 1) * percent
+    floor = math.floor(index)
+    ceil = math.ceil(index)
+    if floor == ceil:
+        return arr[int(index)]
+    low_value = arr[int(floor)] * (ceil - index)
+    high_value = arr[int(ceil)] * (index - floor)
+    return low_value + high_value
+
+
+class FLACConverter(object): # pylint: disable=too-few-public-methods
+    """
+    Class for converting a region of an input audio or video file into a FLAC audio file
+    """
+    def __init__(self, source_path, include_before=0.25, include_after=0.25):
+        self.source_path = source_path
+        self.include_before = include_before
+        self.include_after = include_after
+
+    def __call__(self, region):
+        try:
+            start, end = region
+            start = max(0, start - self.include_before)
+            end += self.include_after
+            #delete=False necessary for running on Windows
+            temp = tempfile.NamedTemporaryFile(suffix='.flac', delete=False)
+            program_ffmpeg = which("ffmpeg")
+            command = [str(program_ffmpeg), "-ss", str(start), "-t", str(end - start),
+                       "-y", "-i", self.source_path,
+                       "-loglevel", "error", temp.name]
+            use_shell = True if os.name == "nt" else False
+            subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+            read_data = temp.read()
+            temp.close()
+            os.unlink(temp.name)
+            return read_data
+
+        except KeyboardInterrupt:
+            return None
+
+
+class SpeechRecognizer(object): # pylint: disable=too-few-public-methods
+    """
+    Class for performing speech-to-text for an input FLAC file.
+    """
+    def __init__(self, language="en", rate=44100, retries=3, api_key=GOOGLE_SPEECH_API_KEY):
+        self.language = language
+        self.rate = rate
+        self.api_key = api_key
+        self.retries = retries
+
+    def __call__(self, data):
+        try:
+            for _ in range(self.retries):
+                url = GOOGLE_SPEECH_API_URL.format(lang=self.language, key=self.api_key)
+                headers = {"Content-Type": "audio/x-flac; rate=%d" % self.rate}
+
+                try:
+                    resp = requests.post(url, data=data, headers=headers)
+                except requests.exceptions.ConnectionError:
+                    continue
+
+                for line in resp.content.decode('utf-8').split("\n"):
+                    try:
+                        line = json.loads(line)
+                        line = line['result'][0]['alternative'][0]['transcript']
+                        return line[:1].upper() + line[1:]
+                    except IndexError:
+                        # no result
+                        continue
+                    except JSONDecodeError:
+                        continue
+
+        except KeyboardInterrupt:
+            return None
+
+
+class Translator(object): # pylint: disable=too-few-public-methods
+    """
+    Class for translating a sentence from a one language to another.
+    """
+    def __init__(self, language, api_key, src, dst):
+        self.language = language
+        self.api_key = api_key
+        self.service = build('translate', 'v2',
+                             developerKey=self.api_key)
+        self.src = src
+        self.dst = dst
+
+    def __call__(self, sentence):
+        try:
+            if not sentence:
+                return None
+
+            result = self.service.translations().list( # pylint: disable=no-member
+                source=self.src,
+                target=self.dst,
+                q=[sentence]
+            ).execute()
+
+            if 'translations' in result and result['translations'] and \
+                'translatedText' in result['translations'][0]:
+                return result['translations'][0]['translatedText']
+
+            return None
+
+        except KeyboardInterrupt:
+            return None
+
+
+def which(program):
+    """
+    Return the path for a given executable.
+    """
+    def is_exe(file_path):
+        """
+        Checks whether a file is executable.
+        """
+        return os.path.isfile(file_path) and os.access(file_path, os.X_OK)
+    #necessary to run on Windows
+    if os.name == "nt":
+        program += ".exe"
+    fpath, _ = os.path.split(program)
+    if fpath:
+        if is_exe(program):
+            return program
+    else:
+        #looks for file in the script execution folder before checking on system path
+        current_dir = os.getcwd()
+        local_program = os.path.join(current_dir, program)
+        if is_exe(local_program):
+            return local_program
+        else:
+            for path in os.environ["PATH"].split(os.pathsep):
+                path = path.strip('"')
+                exe_file = os.path.join(path, program)
+                if is_exe(exe_file):
+                    return exe_file
+    return None
+
+
+def extract_audio(filename, channels=1, rate=16000):
+    """
+    Extract audio from an input file to a temporary WAV file.
+    """
+    temp = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
+    if not os.path.isfile(filename):
+        print("The given file does not exist: {}".format(filename))
+        raise Exception("Invalid filepath: {}".format(filename))
+    program_ffmpeg = which("ffmpeg")
+    if not program_ffmpeg:
+        print("ffmpeg: Executable not found on machine.")
+        raise Exception("Dependency not found: ffmpeg")
+    command = [str(program_ffmpeg), "-y", "-i", filename,
+               "-ac", str(channels), "-ar", str(rate),
+               "-loglevel", "error", temp.name]
+    use_shell = True if os.name == "nt" else False
+    subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+    return temp.name, rate
+
+
+def find_speech_regions(filename, frame_width=4096, min_region_size=0.5, max_region_size=6): # pylint: disable=too-many-locals
+    """
+    Perform voice activity detection on a given audio file.
+    """
+    reader = wave.open(filename)
+    sample_width = reader.getsampwidth()
+    rate = reader.getframerate()
+    n_channels = reader.getnchannels()
+    chunk_duration = float(frame_width) / rate
+
+    n_chunks = int(math.ceil(reader.getnframes()*1.0 / frame_width))
+    energies = []
+
+    for _ in range(n_chunks):
+        chunk = reader.readframes(frame_width)
+        energies.append(audioop.rms(chunk, sample_width * n_channels))
+
+    threshold = percentile(energies, 0.2)
+
+    elapsed_time = 0
+
+    regions = []
+    region_start = None
+
+    for energy in energies:
+        is_silence = energy <= threshold
+        max_exceeded = region_start and elapsed_time - region_start >= max_region_size
+
+        if (max_exceeded or is_silence) and region_start:
+            if elapsed_time - region_start >= min_region_size:
+                regions.append((region_start, elapsed_time))
+                region_start = None
+
+        elif (not region_start) and (not is_silence):
+            region_start = elapsed_time
+        elapsed_time += chunk_duration
+    return regions
+
+
+def generate_subtitles( # pylint: disable=too-many-locals,too-many-arguments
+        source_path,
+        output=None,
+        concurrency=DEFAULT_CONCURRENCY,
+        src_language=DEFAULT_SRC_LANGUAGE,
+        dst_language=DEFAULT_DST_LANGUAGE,
+        subtitle_file_format=DEFAULT_SUBTITLE_FORMAT,
+        api_key=None,
+    ):
+    """
+    Given an input audio/video file, generate subtitles in the specified language and format.
+    """
+
+    if os.name != "nt" and "Darwin" in os.uname():
+        #the default unix fork method does not work on Mac OS
+        #need to use forkserver
+        if 'forkserver' != multiprocessing.get_start_method(allow_none=True):
+            multiprocessing.set_start_method('forkserver')
+
+    audio_filename, audio_rate = extract_audio(source_path)
+
+    regions = find_speech_regions(audio_filename)
+
+    pool = multiprocessing.Pool(concurrency)
+    converter = FLACConverter(source_path=audio_filename)
+    recognizer = SpeechRecognizer(language=src_language, rate=audio_rate,
+                                  api_key=GOOGLE_SPEECH_API_KEY)
+
+    transcripts = []
+    if regions:
+        try:
+            widgets = ["Converting speech regions to FLAC files: ", Percentage(), ' ', Bar(), ' ',
+                       ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+            extracted_regions = []
+            for i, extracted_region in enumerate(pool.imap(converter, regions)):
+                extracted_regions.append(extracted_region)
+                pbar.update(i)
+            pbar.finish()
+
+            widgets = ["Performing speech recognition: ", Percentage(), ' ', Bar(), ' ', ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+
+            for i, transcript in enumerate(pool.imap(recognizer, extracted_regions)):
+                transcripts.append(transcript)
+                pbar.update(i)
+            pbar.finish()
+
+            if src_language.split("-")[0] != dst_language.split("-")[0]:
+                if api_key:
+                    google_translate_api_key = api_key
+                    translator = Translator(dst_language, google_translate_api_key,
+                                            dst=dst_language,
+                                            src=src_language)
+                    prompt = "Translating from {0} to {1}: ".format(src_language, dst_language)
+                    widgets = [prompt, Percentage(), ' ', Bar(), ' ', ETA()]
+                    pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+                    translated_transcripts = []
+                    for i, transcript in enumerate(pool.imap(translator, transcripts)):
+                        translated_transcripts.append(transcript)
+                        pbar.update(i)
+                    pbar.finish()
+                    transcripts = translated_transcripts
+                else:
+                    print(
+                        "Error: Subtitle translation requires specified Google Translate API key. "
+                        "See --help for further information."
+                    )
+                    return 1
+
+        except KeyboardInterrupt:
+            pbar.finish()
+            pool.terminate()
+            pool.join()
+            print("Cancelling transcription")
+            raise
+
+    timed_subtitles = [(r, t) for r, t in zip(regions, transcripts) if t]
+    formatter = FORMATTERS.get(subtitle_file_format)
+    formatted_subtitles = formatter(timed_subtitles)
+
+    dest = output
+
+    if not dest:
+        base = os.path.splitext(source_path)[0]
+        dest = "{base}.{format}".format(base=base, format=subtitle_file_format)
+
+    with open(dest, 'wb') as output_file:
+        output_file.write(formatted_subtitles.encode("utf-8"))
+
+    os.remove(audio_filename)
+
+    return dest
+
+
+def validate(args):
+    """
+    Check that the CLI arguments passed to autosub are valid.
+    """
+    if args.format not in FORMATTERS:
+        print(
+            "Subtitle format not supported. "
+            "Run with --list-formats to see all supported formats."
+        )
+        return False
+
+    if args.src_language not in LANGUAGE_CODES.keys():
+        print(
+            "Source language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if args.dst_language not in LANGUAGE_CODES.keys():
+        print(
+            "Destination language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if not args.source_path:
+        print("Error: You need to specify a source path.")
+        return False
+
+    return True
+
+
+def main():
+    """
+    Run autosub as a command-line program.
+    """
+    parser = argparse.ArgumentParser()
+    parser.add_argument('source_path', help="Path to the video or audio file to subtitle",
+                        nargs='?')
+    parser.add_argument('-C', '--concurrency', help="Number of concurrent API requests to make",
+                        type=int, default=DEFAULT_CONCURRENCY)
+    parser.add_argument('-o', '--output',
+                        help="Output path for subtitles (by default, subtitles are saved in \
+                        the same directory and name as the source path)")
+    parser.add_argument('-F', '--format', help="Destination subtitle format",
+                        default=DEFAULT_SUBTITLE_FORMAT)
+    parser.add_argument('-S', '--src-language', help="Language spoken in source file",
+                        default=DEFAULT_SRC_LANGUAGE)
+    parser.add_argument('-D', '--dst-language', help="Desired language for the subtitles",
+                        default=DEFAULT_DST_LANGUAGE)
+    parser.add_argument('-K', '--api-key',
+                        help="The Google Translate API key to be used. \
+                        (Required for subtitle translation)")
+    parser.add_argument('--list-formats', help="List all available subtitle formats",
+                        action='store_true')
+    parser.add_argument('--list-languages', help="List all available source/destination languages",
+                        action='store_true')
+
+    args = parser.parse_args()
+
+    if args.list_formats:
+        print("List of formats:")
+        for subtitle_format in FORMATTERS:
+            print("{format}".format(format=subtitle_format))
+        return 0
+
+    if args.list_languages:
+        print("List of all languages:")
+        for code, language in sorted(LANGUAGE_CODES.items()):
+            print("{code}\t{language}".format(code=code, language=language))
+        return 0
+
+    if not validate(args):
+        return 1
+
+    try:
+        subtitle_file_path = generate_subtitles(
+            source_path=args.source_path,
+            concurrency=args.concurrency,
+            src_language=args.src_language,
+            dst_language=args.dst_language,
+            api_key=args.api_key,
+            subtitle_file_format=args.format,
+            output=args.output,
+        )
+        print("Subtitles file created at {}".format(subtitle_file_path))
+    except KeyboardInterrupt:
+        return 1
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())

BIN
autoSub_dev/autosub/__pycache__/__init__.cpython-37.pyc


BIN
autoSub_dev/autosub/__pycache__/__init__.cpython-38.pyc


BIN
autoSub_dev/autosub/__pycache__/__init__.cpython-39.pyc


BIN
autoSub_dev/autosub/__pycache__/constants.cpython-37.pyc


BIN
autoSub_dev/autosub/__pycache__/constants.cpython-38.pyc


BIN
autoSub_dev/autosub/__pycache__/constants.cpython-39.pyc


BIN
autoSub_dev/autosub/__pycache__/formatters.cpython-37.pyc


BIN
autoSub_dev/autosub/__pycache__/formatters.cpython-38.pyc


BIN
autoSub_dev/autosub/__pycache__/formatters.cpython-39.pyc


+ 118 - 0
autoSub_dev/autosub/constants.py

@@ -0,0 +1,118 @@
+"""
+Defines constants used by autosub.s
+"""
+
+from __future__ import unicode_literals
+
+GOOGLE_SPEECH_API_KEY = "AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw"
+GOOGLE_SPEECH_API_URL = "http://www.google.com/speech-api/v2/recognize?client=chromium&lang={lang}&key={key}" # pylint: disable=line-too-long
+
+LANGUAGE_CODES = {
+    'af': 'Afrikaans',
+    'ar': 'Arabic',
+    'az': 'Azerbaijani',
+    'be': 'Belarusian',
+    'bg': 'Bulgarian',
+    'bn': 'Bengali',
+    'bs': 'Bosnian',
+    'ca': 'Catalan',
+    'ceb': 'Cebuano',
+    'cs': 'Czech',
+    'cy': 'Welsh',
+    'da': 'Danish',
+    'de': 'German',
+    'el': 'Greek',
+    'en-AU': 'English (Australia)',
+    'en-CA': 'English (Canada)',
+    'en-GB': 'English (United Kingdom)',
+    'en-IN': 'English (India)',
+    'en-IE': 'English (Ireland)',
+    'en-NZ': 'English (New Zealand)',
+    'en-PH': 'English (Philippines)',
+    'en-SG': 'English (Singapore)',
+    'en-US': 'English (United States)',
+    'eo': 'Esperanto',
+    'es-AR': 'Spanish (Argentina)',
+    'es-CL': 'Spanish (Chile)',
+    'es-ES': 'Spanish (Spain)',
+    'es-US': 'Spanish (United States)',
+    'es-MX': 'Spanish (Mexico)',
+    'es': 'Spanish',
+    'et': 'Estonian',
+    'eu': 'Basque',
+    'fa': 'Persian',
+    'fi': 'Finnish',
+    'fr': 'French',
+    'ga': 'Irish',
+    'gl': 'Galician',
+    'gu': 'Gujarati',
+    'ha': 'Hausa',
+    'hi': 'Hindi',
+    'hmn': 'Hmong',
+    'hr': 'Croatian',
+    'ht': 'Haitian Creole',
+    'hu': 'Hungarian',
+    'hy': 'Armenian',
+    'id': 'Indonesian',
+    'ig': 'Igbo',
+    'is': 'Icelandic',
+    'it': 'Italian',
+    'iw': 'Hebrew',
+    'ja': 'Japanese',
+    'jw': 'Javanese',
+    'ka': 'Georgian',
+    'kk': 'Kazakh',
+    'km': 'Khmer',
+    'kn': 'Kannada',
+    'ko': 'Korean',
+    'la': 'Latin',
+    'lo': 'Lao',
+    'lt': 'Lithuanian',
+    'lv': 'Latvian',
+    'mg': 'Malagasy',
+    'mi': 'Maori',
+    'mk': 'Macedonian',
+    'ml': 'Malayalam',
+    'mn': 'Mongolian',
+    'mr': 'Marathi',
+    'ms': 'Malay',
+    'mt': 'Maltese',
+    'my': 'Myanmar (Burmese)',
+    'ne': 'Nepali',
+    'nl': 'Dutch',
+    'no': 'Norwegian',
+    'ny': 'Chichewa',
+    'pa': 'Punjabi',
+    'pl': 'Polish',
+    'pt-BR': 'Portuguese (Brazil)',
+    'pt-PT': 'Portuguese (Portugal)',
+    'ro': 'Romanian',
+    'ru': 'Russian',
+    'si': 'Sinhala',
+    'sk': 'Slovak',
+    'sl': 'Slovenian',
+    'so': 'Somali',
+    'sq': 'Albanian',
+    'sr': 'Serbian',
+    'st': 'Sesotho',
+    'su': 'Sudanese',
+    'sv': 'Swedish',
+    'sw': 'Swahili',
+    'ta': 'Tamil',
+    'te': 'Telugu',
+    'tg': 'Tajik',
+    'th': 'Thai',
+    'tl': 'Filipino',
+    'tr': 'Turkish',
+    'uk': 'Ukrainian',
+    'ur': 'Urdu',
+    'uz': 'Uzbek',
+    'vi': 'Vietnamese',
+    'yi': 'Yiddish',
+    'yo': 'Yoruba',
+    'yue-Hant-HK': 'Cantonese, (Traditional HK)',
+    'zh': 'Chinese (Simplified, China)',
+    'zh-HK': 'Chinese (Simplified, Hong Kong)',
+    'zh-TW': 'Chinese (Traditional, Taiwan)',
+    'zu': 'Zulu',
+}

+ 66 - 0
autoSub_dev/autosub/formatters.py

@@ -0,0 +1,66 @@
+"""
+Defines subtitle formatters used by autosub.s
+"""
+
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import json
+
+import pysrt
+import six
+
+
+def srt_formatter(subtitles, padding_before=0, padding_after=0):
+    """
+    Serialize a list of subtitles according to the SRT format, with optional time padding.
+    """
+    sub_rip_file = pysrt.SubRipFile()
+    for i, ((start, end), text) in enumerate(subtitles, start=1):
+        item = pysrt.SubRipItem()
+        item.index = i
+        item.text = six.text_type(text)
+        item.start.seconds = max(0, start - padding_before)
+        item.end.seconds = end + padding_after
+        sub_rip_file.append(item)
+    return '\n'.join(six.text_type(item) for item in sub_rip_file)
+
+
+def vtt_formatter(subtitles, padding_before=0, padding_after=0):
+    """
+    Serialize a list of subtitles according to the VTT format, with optional time padding.
+    """
+    text = srt_formatter(subtitles, padding_before, padding_after)
+    text = 'WEBVTT\n\n' + text.replace(',', '.')
+    return text
+
+
+def json_formatter(subtitles):
+    """
+    Serialize a list of subtitles as a JSON blob.
+    """
+    subtitle_dicts = [
+        {
+            'start': start,
+            'end': end,
+            'content': text,
+        }
+        for ((start, end), text)
+        in subtitles
+    ]
+    return json.dumps(subtitle_dicts)
+
+
+def raw_formatter(subtitles):
+    """
+    Serialize a list of subtitles as a newline-delimited string.
+    """
+    return ' '.join(text for (_rng, text) in subtitles)
+
+
+FORMATTERS = {
+    'srt': srt_formatter,
+    'vtt': vtt_formatter,
+    'json': json_formatter,
+    'raw': raw_formatter,
+}

BIN
autoSub_dev/pytranscriber/.DS_Store


+ 0 - 0
autoSub_dev/pytranscriber/control/__init__.py


BIN
autoSub_dev/pytranscriber/control/__pycache__/__init__.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/__init__.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/__init__.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/ctr_autosub.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/ctr_autosub.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/ctr_autosub.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/ctr_main.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/ctr_main.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/ctr_main.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/thread_cancel_autosub.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/thread_cancel_autosub.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/thread_cancel_autosub.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/thread_exec_autosub.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/thread_exec_autosub.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/control/__pycache__/thread_exec_autosub.cpython-39.pyc


+ 145 - 0
autoSub_dev/pytranscriber/control/ctr_autosub.py

@@ -0,0 +1,145 @@
+from autosub import FLACConverter
+from autosub import SpeechRecognizer
+from autosub import extract_audio
+from autosub import find_speech_regions
+from autosub import DEFAULT_CONCURRENCY
+from autosub import DEFAULT_SUBTITLE_FORMAT
+from autosub import GOOGLE_SPEECH_API_KEY
+from autosub.formatters import FORMATTERS
+
+import multiprocessing
+import time
+import os
+
+from pytranscriber.util.util import MyUtil
+
+
+class Ctr_Autosub():
+
+    cancel = False
+
+    @staticmethod
+    def init():
+        Ctr_Autosub.cancel = False
+
+    @staticmethod
+    def is_operation_canceled():
+        return Ctr_Autosub.cancel
+
+
+    @staticmethod
+    def output_progress(listener_progress, str_task, progress_percent):
+        # only update progress if not requested to cancel
+        if not Ctr_Autosub.cancel:
+            listener_progress(str_task, progress_percent)
+
+    @staticmethod
+    def cancel_operation():
+        Ctr_Autosub.cancel = True
+
+        while Ctr_Autosub.step == 0:
+            time.sleep(0.1)
+
+        # the first step involves ffmpeg and cannot be stopped safely
+        if Ctr_Autosub.step == 1:
+            # close wait for threads to finish their work first
+            Ctr_Autosub.pool.close()
+            Ctr_Autosub.pool.join()
+
+        else:
+            # terminates the threads immediately
+            Ctr_Autosub.pool.terminate()
+            Ctr_Autosub.pool.join()
+
+    @staticmethod
+    def generate_subtitles(# pylint: disable=too-many-locals,too-many-arguments
+            source_path,
+            src_language,
+            listener_progress,
+            output=None,
+            concurrency=DEFAULT_CONCURRENCY,
+            subtitle_file_format=DEFAULT_SUBTITLE_FORMAT
+        ):
+
+        # windows not support forkserver... only spawn
+        if os.name != "nt" and "Darwin" in os.uname():
+            # necessary for running on MacOS
+            # method can be set only once, otherwise crash
+            #from python 3.8 above the default for macos is spawn and not fork
+            if 'spawn' != multiprocessing.get_start_method(allow_none=True):
+                multiprocessing.set_start_method('spawn')
+        Ctr_Autosub.cancel = False
+        Ctr_Autosub.step = 0
+        """
+        Given an input audio/video file, generate subtitles in the specified language and format.
+        """
+        audio_filename, audio_rate = extract_audio(source_path)
+
+        regions = find_speech_regions(audio_filename)
+
+        converter = FLACConverter(source_path=audio_filename)
+        recognizer = SpeechRecognizer(language=src_language, rate=audio_rate,
+                                      api_key=GOOGLE_SPEECH_API_KEY)
+        transcripts = []
+        if regions:
+            try:
+                if Ctr_Autosub.cancel:
+                    return -1
+
+                str_task_1 = "Step 1 of 2: Converting speech regions to FLAC files "
+                len_regions = len(regions)
+                extracted_regions = []
+                Ctr_Autosub.pool = multiprocessing.Pool(concurrency)
+                for i, extracted_region in enumerate(Ctr_Autosub.pool.imap(converter, regions)):
+                    Ctr_Autosub.step = 1
+                    extracted_regions.append(extracted_region)
+                    progress_percent = MyUtil.percentage(i, len_regions)
+                    Ctr_Autosub.output_progress(listener_progress, str_task_1, progress_percent)
+                if Ctr_Autosub.cancel:
+                    return -1
+                else:
+                    Ctr_Autosub.pool.close()
+                    Ctr_Autosub.pool.join()
+
+                str_task_2 = "Step 2 of 2: Performing speech recognition "
+                Ctr_Autosub.pool = multiprocessing.Pool(concurrency)
+                for i, transcript in enumerate(Ctr_Autosub.pool.imap(recognizer, extracted_regions)):
+                    Ctr_Autosub.step = 2
+                    transcripts.append(transcript)
+                    progress_percent = MyUtil.percentage(i, len_regions)
+                    Ctr_Autosub.output_progress(listener_progress, str_task_2, progress_percent)
+
+                if Ctr_Autosub.cancel:
+                    return -1
+                else:
+                    Ctr_Autosub.pool.close()
+                    Ctr_Autosub.pool.join()
+
+            except KeyboardInterrupt:
+                Ctr_Autosub.pbar.finish()
+                Ctr_Autosub.pool.terminate()
+                Ctr_Autosub.pool.join()
+                raise
+
+        timed_subtitles = [(r, t) for r, t in zip(regions, transcripts) if t]
+        formatter = FORMATTERS.get(subtitle_file_format)
+        formatted_subtitles = formatter(timed_subtitles)
+
+        dest = output
+
+        if not dest:
+            base = os.path.splitext(source_path)[0]
+            dest = "{base}.{format}".format(base=base, format=subtitle_file_format)
+
+        with open(dest, 'wb') as output_file:
+            output_file.write(formatted_subtitles.encode("utf-8"))
+
+        os.remove(audio_filename)
+
+        if Ctr_Autosub.cancel:
+            return -1
+        else:
+            Ctr_Autosub.pool.close()
+            Ctr_Autosub.pool.join()
+
+        return dest

+ 413 - 0
autoSub_dev/pytranscriber/control/ctr_main.py

@@ -0,0 +1,413 @@
+'''
+   (C) 2019 Raryel C. Souza
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+'''
+
+from PyQt5 import QtCore, QtWidgets
+from PyQt5.QtWidgets import QFileDialog, QMessageBox
+from PyQt5.QtCore import Qt
+from pathlib import Path
+from pytranscriber.model.param_autosub import Param_Autosub
+from pytranscriber.util.util import MyUtil
+from pytranscriber.control.thread_exec_autosub import Thread_Exec_Autosub
+from pytranscriber.control.thread_cancel_autosub import Thread_Cancel_Autosub
+from pytranscriber.gui.gui import Ui_window
+import os
+
+
+class Ctr_Main():
+
+    def __init__(self):
+        import sys
+        app = QtWidgets.QApplication(sys.argv)
+        window = QtWidgets.QMainWindow()
+        self.objGUI = Ui_window()
+        self.objGUI.setupUi(window)
+        self.__initGUI()
+        window.setFixedSize(window.size())
+        window.show()
+        sys.exit(app.exec_())
+
+
+
+    def __initGUI(self):
+
+        #language selection list
+        list_languages =  [ "en-US - English (United States)",
+                            "en-AU - English (Australia)",
+                            "en-CA - English (Canada)",
+                            "en-GB - English (United Kingdom)",
+                            "en-HK - English (Hong Kong)",
+                            "en-IN - English (India)",
+                            "en-GB - English (Ireland)",
+                            "en-NZ - English (New Zealand)",
+                            "en-PH - English (Philippines)",
+                            "en-SG - English (Singapore)",
+                            "af - Afrikaans",
+                            "ar - Arabic",
+                            'ar-DZ - Arabic (Algeria)',
+                            'ar-EG - Arabic (Egypt)',
+                            'ar-IQ - Arabic (Iraq)',
+                            'ar-IS - Arabic (Israel)',
+                            'ar-JO - Arabic (Jordan)',
+                            'ar-KW - Arabic (Kuwait)',
+                            'ar-LB - Arabic (Lebanon)',
+                            'ar-MA - Arabic (Morocco)',
+                            'ar-OM - Arabic (Oman)',
+                            'ar-QA - Arabic (Qatar)',
+                            'ar-SA - Arabic (Saudi Arabia)',
+                            'ar-PS - Arabic (State of Palestine)',
+                            'ar-TN - Arabic (Tunisia)',
+                            'ar-AE - Arabic (United Arab Emirates)',
+                            'ar-YE - Arabic (Yemen)',
+                            "az - Azerbaijani",
+                            "be - Belarusian",
+                            "bg - Bulgarian",
+                            "bn - Bengali",
+                            "bs - Bosnian",
+                            "ca - Catalan",
+                            "ceb -Cebuano",
+                            "cs - Czech",
+                            "cy - Welsh",
+                            "da - Danish",
+                            "de - German",
+                            'de-AT - German (Austria)',
+                            'de-CH - German (Switzerland)',
+                            "el - Greek",
+                            "eo - Esperanto",
+                            'es-ES - Spanish (Spain)',
+                            'es-AR - Spanish (Argentina)',
+                            'es-BO - Spanish (Bolivia)',
+                            'es-CL - Spanish (Chile)',
+                            'es-CO - Spanish (Colombia)',
+                            'es-CR - Spanish (Costa Rica)',
+                            'es-DO - Spanish (Dominican Republic)',
+                            'es-EC - Spanish (Ecuador)',
+                            'es-GT - Spanish (Guatemala)',
+                            'es-HN - Spanish (Honduras)',
+                            'es-MX - Spanish (Mexico)',
+                            'es-NI - Spanish (Nicaragua)',
+                            'es-PA - Spanish (Panama)',
+                            'es-PE - Spanish (Peru)',
+                            'es-PR - Spanish (Puerto Rico)',
+                            'es-PY - Spanish (Paraguay)',
+                            'es-SV - Spanish (El Salvador)',
+                            'es-UY - Spanish (Uruguay)',
+                            'es-US - Spanish (United States)',
+                            'es-VE - Spanish (Venezuela)',
+                            "et - Estonian",
+                            "eu - Basque",
+                            "fa - Persian",
+                            'fil-PH - Filipino (Philippines)',
+                            "fi - Finnish",
+                            "fr - French",
+                            'fr-BE - French (Belgium)',
+                            'fr-CA - French (Canada)',
+                            'fr-CH - French (Switzerland)',
+                            "ga - Irish",
+                            "gl - Galician",
+                            "gu -Gujarati",
+                            "ha - Hausa",
+                            "hi - Hindi",
+                            "hmn - Hmong",
+                            "hr - Croatian",
+                            "ht - Haitian Creole",
+                            "hu - Hungarian",
+                            "hy - Armenian",
+                            "id - Indonesian",
+                            "ig - Igbo",
+                            "is - Icelandic",
+                            "it - Italian",
+                            'it-CH - Italian (Switzerland)',
+                            "iw - Hebrew",
+                            "ja - Japanese",
+                            "jw - Javanese",
+                            "ka - Georgian",
+                            "kk - Kazakh",
+                            "km - Khmer",
+                            "kn - Kannada",
+                            "ko - Korean",
+                            "la - Latin",
+                            "lo - Lao",
+                            "lt - Lithuanian",
+                            "lv - Latvian",
+                            "mg - Malagasy",
+                            "mi - Maori",
+                            "mk - Macedonian",
+                            "ml - Malayalam",
+                            "mn - Mongolian",
+                            "mr - Marathi",
+                            "ms - Malay",
+                            "mt - Maltese",
+                            "my - Myanmar (Burmese)",
+                            "ne - Nepali",
+                            "nl - Dutch",
+                            "no - Norwegian",
+                            "ny - Chichewa",
+                            "pa - Punjabi",
+                            "pl - Polish",
+                            "pt-BR - Portuguese (Brazil)",
+                            "pt-PT - Portuguese (Portugal)",
+                            "ro - Romanian",
+                            "ru - Russian",
+                            "si - Sinhala",
+                            "sk - Slovak",
+                            "sl - Slovenian",
+                            "so - Somali",
+                            "sq - Albanian",
+                            "sr - Serbian",
+                            "st - Sesotho",
+                            "su - Sudanese",
+                            "sv - Swedish",
+                            "sw - Swahili",
+                            "ta - Tamil",
+                            'ta-IN - Tamil (India)',
+                            'ta-MY - Tamil (Malaysia)',
+                            'ta-SG - Tamil (Singapore)',
+                            'ta-LK - Tamil (Sri Lanka)',
+                            "te - Telugu",
+                            "tg - Tajik",
+                            "th - Thai",
+                            "tl - Filipino",
+                            "tr - Turkish",
+                            "uk - Ukrainian",
+                            "ur - Urdu",
+                            "uz - Uzbek",
+                            "vi - Vietnamese",
+                            "yi - Yiddish",
+                            "yo - Yoruba",
+                            "yue-Hant-HK - Cantonese (Traditional, HK)",
+                            "zh - Chinese (Simplified, China)",
+                            "zh-HK - Chinese (Simplified, Hong Kong)",
+                            "zh-TW - Chinese (Traditional, Taiwan)",
+                            "zu - Zulu" ]
+
+        self.objGUI.cbSelectLang.addItems(list_languages)
+        self.__listenerProgress("", 0)
+
+        #default output folder at user desktop
+        userHome = Path.home()
+        pathOutputFolder = userHome / 'Desktop' / 'pyTranscriber'
+        self.objGUI.qleOutputFolder.setText(str(pathOutputFolder))
+
+        self.objGUI.bRemoveFile.setEnabled(False)
+
+        self.objGUI.bCancel.hide()
+
+        #button listeners
+        self.objGUI.bConvert.clicked.connect(self.__listenerBExec)
+        self.objGUI.bCancel.clicked.connect(self.__listenerBCancel)
+        self.objGUI.bRemoveFile.clicked.connect(self.__listenerBRemove)
+        self.objGUI.bSelectOutputFolder.clicked.connect(self.__listenerBSelectOuputFolder)
+        self.objGUI.bOpenOutputFolder.clicked.connect(self.__listenerBOpenOutputFolder)
+        self.objGUI.bSelectMedia.clicked.connect(self.__listenerBSelectMedia)
+
+        self.objGUI.actionLicense.triggered.connect(self.__listenerBLicense)
+        self.objGUI.actionDonation.triggered.connect(self.__listenerBDonation)
+        self.objGUI.actionAbout_pyTranscriber.triggered.connect(self.__listenerBAboutpyTranscriber)
+
+    def __resetGUIAfterSuccess(self):
+        self.__resetGUIAfterCancel()
+
+        self.objGUI.qlwListFilesSelected.clear()
+        self.objGUI.bConvert.setEnabled(False)
+        self.objGUI.bRemoveFile.setEnabled(False)
+
+    def __resetGUIAfterCancel(self):
+
+        self.__resetProgressBar()
+
+        self.objGUI.bSelectMedia.setEnabled(True)
+        self.objGUI.bSelectOutputFolder.setEnabled(True)
+        self.objGUI.cbSelectLang.setEnabled(True)
+        self.objGUI.chbxOpenOutputFilesAuto.setEnabled(True)
+
+        self.objGUI.bCancel.hide()
+        self.objGUI.bConvert.setEnabled(True)
+        self.objGUI.bRemoveFile.setEnabled(True)
+
+    def __lockButtonsDuringOperation(self):
+        self.objGUI.bConvert.setEnabled(False)
+        self.objGUI.bRemoveFile.setEnabled(False)
+        self.objGUI.bSelectMedia.setEnabled(False)
+        self.objGUI.bSelectOutputFolder.setEnabled(False)
+        self.objGUI.cbSelectLang.setEnabled(False)
+        self.objGUI.chbxOpenOutputFilesAuto.setEnabled(False)
+        QtCore.QCoreApplication.processEvents()
+
+    def __listenerProgress(self, str, percent):
+        self.objGUI.labelCurrentOperation.setText(str)
+        self.objGUI.progressBar.setProperty("value", percent)
+        QtCore.QCoreApplication.processEvents()
+
+    def __setProgressBarIndefinite(self):
+        self.objGUI.progressBar.setMinimum(0)
+        self.objGUI.progressBar.setMaximum(0)
+        self.objGUI.progressBar.setValue(0)
+
+    def __resetProgressBar(self):
+        self.objGUI.progressBar.setMinimum(0)
+        self.objGUI.progressBar.setMaximum(100)
+        self.objGUI.progressBar.setValue(0)
+        self.__listenerProgress("", 0)
+
+    def __updateProgressFileYofN(self, str):
+        self.objGUI.labelProgressFileIndex.setText(str)
+        QtCore.QCoreApplication.processEvents()
+
+    def __listenerBSelectOuputFolder(self):
+        fSelectDir = QFileDialog.getExistingDirectory(self.objGUI.centralwidget)
+        if fSelectDir:
+            self.objGUI.qleOutputFolder.setText(fSelectDir)
+
+    def __listenerBSelectMedia(self):
+        #options = QFileDialog.Options()
+        options = QFileDialog.DontUseNativeDialog
+        files, _ = QFileDialog.getOpenFileNames(self.objGUI.centralwidget, "Select media", "","All Media Files (*.mp3 *.mp4 *.wav *.m4a *.wma)")
+
+        if files:
+            self.objGUI.qlwListFilesSelected.addItems(files)
+
+            #enable the convert button only if list of files is not empty
+            self.objGUI.bConvert.setEnabled(True)
+            self.objGUI.bRemoveFile.setEnabled(True)
+
+
+    def __listenerBExec(self):
+        if not MyUtil.is_internet_connected():
+            self.__showErrorMessage("Error! Cannot reach Google Speech Servers. \n\n1) Please make sure you are connected to the internet. \n2) If you are in China or other place that blocks access to Google servers: please install and enable a desktop-wide VPN app like Windscribe before trying to use pyTranscriber!")
+        else:
+            #extracts the two letter lang_code from the string on language selection
+            selectedLanguage = self.objGUI.cbSelectLang.currentText()
+            indexSpace = selectedLanguage.index(" ")
+            langCode = selectedLanguage[:indexSpace]
+
+            listFiles = []
+            for i in range(self.objGUI.qlwListFilesSelected.count()):
+                listFiles.append(str(self.objGUI.qlwListFilesSelected.item(i).text()))
+
+            outputFolder = self.objGUI.qleOutputFolder.text()
+
+            if self.objGUI.chbxOpenOutputFilesAuto.checkState() == Qt.Checked:
+                boolOpenOutputFilesAuto = True
+            else:
+                boolOpenOutputFilesAuto = False
+
+            objParamAutosub = Param_Autosub(listFiles, outputFolder, langCode,
+                                            boolOpenOutputFilesAuto)
+
+            #execute the main process in separate thread to avoid gui lock
+            self.thread_exec = Thread_Exec_Autosub(objParamAutosub)
+
+            #connect signals from work thread to gui controls
+            self.thread_exec.signalLockGUI.connect(self.__lockButtonsDuringOperation)
+            self.thread_exec.signalResetGUIAfterSuccess.connect(self.__resetGUIAfterSuccess)
+            self.thread_exec.signalResetGUIAfterCancel.connect(self.__resetGUIAfterCancel)
+            self.thread_exec.signalProgress.connect(self.__listenerProgress)
+            self.thread_exec.signalProgressFileYofN.connect(self.__updateProgressFileYofN)
+            self.thread_exec.signalErrorMsg.connect(self.__showErrorMessage)
+            self.thread_exec.start()
+
+            #Show the cancel button
+            self.objGUI.bCancel.show()
+            self.objGUI.bCancel.setEnabled(True)
+
+    def __listenerBCancel(self):
+        self.objGUI.bCancel.setEnabled(False)
+        self.thread_cancel = Thread_Cancel_Autosub(self.thread_exec)
+
+        #Only if worker thread is running
+        if self.thread_exec and self.thread_exec.isRunning():
+            #reset progress indicator
+            self.__listenerProgress("Cancelling", 0)
+            self.__setProgressBarIndefinite()
+            self.__updateProgressFileYofN("")
+
+            #connect the terminate signal to resetGUI
+            self.thread_cancel.signalTerminated.connect(self.__resetGUIAfterCancel)
+            #run the cancel autosub operation in new thread
+            #to avoid progressbar freezing
+            self.thread_cancel.start()
+            self.thread_exec = None
+
+    def __listenerBRemove(self):
+        indexSelected = self.objGUI.qlwListFilesSelected.currentRow()
+        if indexSelected >= 0:
+            self.objGUI.qlwListFilesSelected.takeItem(indexSelected)
+
+        #if no items left disables the remove and convert button
+        if self.objGUI.qlwListFilesSelected.count() == 0:
+            self.objGUI.bRemoveFile.setEnabled(False)
+            self.objGUI.bConvert.setEnabled(False)
+
+    def __listenerBOpenOutputFolder(self):
+        pathOutputFolder = Path(self.objGUI.qleOutputFolder.text())
+
+        #if folder exists and is valid directory
+        if os.path.exists(pathOutputFolder) and os.path.isdir(pathOutputFolder):
+            MyUtil.open_file(pathOutputFolder)
+        else:
+            self.__showErrorMessage("Error! Invalid output folder.")
+
+    def __listenerBLicense(self):
+        self.__showInfoMessage("<html><body><a href=\"https://www.gnu.org/licenses/gpl-3.0.html\">GPL License</a><br><br>"
+                + "Copyright (C) 2019 Raryel C. Souza <raryel.costa at gmail.com><br>"
+                + "<br>This program is free software: you can redistribute it and/or modify<br>"
+                + "it under the terms of the GNU General Public License as published by<br>"
+                + "the Free Software Foundation, either version 3 of the License, or<br>"
+                + " any later version<br>"
+                + "<br>"
+                + "This program is distributed in the hope that it will be useful,<br>"
+                + "but WITHOUT ANY WARRANTY; without even the implied warranty of<br>"
+                + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>"
+                + "GNU General Public License for more details.<br>"
+                + "<br>"
+                + "You should have received a copy of the GNU General Public License<br>"
+                + "along with this program.  If not, see <a href=\"https://www.gnu.org/licenses\">www.gnu.org/licenses</a>."
+                + "</body></html>", "License")
+
+    def __listenerBDonation(self):
+        self.__showInfoMessage("<html><body>"
+                + "pyTranscriber is developed as a hobby, so donations of any value are welcomed and essential for further improvements and fixes."
+                + "<br><br>If you feel that this software has been useful and would like to contribute for it to continue improve and have more features and fixes you can <a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=YHB854YHPJCU8&item_name=Donation+pyTranscriber&currency_code=BRL\">DONATE VIA PAYPAL</a> or <a href=\"https://blockchain.com/btc/payment_request?address=153LcqV59paxEEJX7riLrEHQbE54vhcko9&amount=0.00026351&message=Donation to support pyTranscriber development\"> DONATE US$5 VIA BITCOIN</a>."
+                + "<br><br>Thanks in advance!"
+                + "</body></html>", "DONATIONS")
+
+    def __listenerBAboutpyTranscriber(self):
+        self.__showInfoMessage("<html><body>"
+                + "<a href=\"https://github.com/raryelcostasouza/pyTranscriber\">pyTranscriber</a> is an application that can be used "
+                + "to generate <b>automatic transcription / automatic subtitles </b>"
+                + "for audio/video files through a friendly graphical user interface. "
+                + "<br><br>"
+                + "The hard work of speech recognition is made by the <a href=\"https://cloud.google.com/speech/\">Google Speech Recognition API</a> "
+                + "using <a href=\"https://github.com/agermanidis/autosub\">Autosub</a>"
+                + "<br><br>pyTranscriber is developed as a hobby, so donations of any value are welcomed and essential for further improvements and fixes."
+                + "<br><br>If you feel that this software has been useful and would like to contribute for it to continue improve and have more features and fixes you can <a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=YHB854YHPJCU8&item_name=Donation+pyTranscriber&currency_code=BRL\">DONATE VIA PAYPAL</a> or <a href=\"https://blockchain.com/btc/payment_request?address=153LcqV59paxEEJX7riLrEHQbE54vhcko9&amount=0.00026351&message=Donation to support pyTranscriber development\"> DONATE US$5 VIA BITCOIN</a>."
+                + "<br><br>Thanks in advance!"
+                + "</body></html>", "About pyTranscriber")
+
+
+    def __showInfoMessage(self, info_msg, title):
+        msg = QMessageBox()
+        msg.setIcon(QMessageBox.Information)
+
+        msg.setWindowTitle(title)
+        msg.setText(info_msg)
+        msg.exec()
+
+    def __showErrorMessage(self, errorMsg):
+        msg = QMessageBox()
+        msg.setIcon(QMessageBox.Critical)
+
+        msg.setWindowTitle("Error!")
+        msg.setText(errorMsg)
+        msg.exec()

+ 14 - 0
autoSub_dev/pytranscriber/control/thread_cancel_autosub.py

@@ -0,0 +1,14 @@
+from PyQt5.QtCore import QThread
+from PyQt5.QtCore import pyqtSignal
+
+
+class Thread_Cancel_Autosub(QThread):
+    signalTerminated = pyqtSignal()
+
+    def __init__(self, pObjWT):
+        self.objWT = pObjWT
+        QThread.__init__(self)
+
+    def run(self):
+        self.objWT.cancel()
+        self.signalTerminated.emit()

+ 120 - 0
autoSub_dev/pytranscriber/control/thread_exec_autosub.py

@@ -0,0 +1,120 @@
+'''
+   (C) 2019 Raryel C. Souza
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+'''
+
+from PyQt5.QtCore import QThread
+from PyQt5.QtCore import pyqtSignal
+from pathlib import Path
+from pytranscriber.util.srtparser import SRTParser
+from pytranscriber.util.util import MyUtil
+from pytranscriber.control.ctr_autosub import Ctr_Autosub
+import os
+
+
+class Thread_Exec_Autosub(QThread):
+    signalLockGUI = pyqtSignal()
+    signalResetGUIAfterCancel = pyqtSignal()
+    signalResetGUIAfterSuccess = pyqtSignal()
+    signalProgress = pyqtSignal(str, int)
+    signalProgressFileYofN = pyqtSignal(str)
+    signalErrorMsg = pyqtSignal(str)
+
+    def __init__(self, objParamAutosub):
+        self.objParamAutosub = objParamAutosub
+        self.running = True
+        QThread.__init__(self)
+
+    def __updateProgressFileYofN(self, currentIndex, countFiles ):
+        self.signalProgressFileYofN.emit("File " + str(currentIndex+1) + " of " +str(countFiles))
+
+    def listenerProgress(self, string, percent):
+        self.signalProgress.emit(string, percent)
+
+    def __generatePathOutputFile(self, sourceFile):
+        #extract the filename without extension from the path
+        base = os.path.basename(sourceFile)
+        #[0] is filename, [1] is file extension
+        fileName = os.path.splitext(base)[0]
+
+        #the output file has same name as input file, located on output Folder
+        #with extension .srt
+        pathOutputFolder = Path(self.objParamAutosub.outputFolder)
+        outputFileSRT = pathOutputFolder / (fileName + ".srt")
+        outputFileTXT = pathOutputFolder / (fileName + ".txt")
+        return [outputFileSRT, outputFileTXT]
+
+    def __runAutosubForMedia(self, index, langCode):
+        sourceFile = self.objParamAutosub.listFiles[index]
+        outputFiles = self.__generatePathOutputFile(sourceFile)
+        outputFileSRT = outputFiles[0]
+        outputFileTXT = outputFiles[1]
+
+        #run autosub
+        fOutput = Ctr_Autosub.generate_subtitles(source_path = sourceFile,
+                                    output = outputFileSRT,
+                                    src_language = langCode,
+                                    listener_progress = self.listenerProgress)
+        #if nothing was returned
+        if not fOutput:
+            self.signalErrorMsg.emit("Error! Unable to generate subtitles for file " + sourceFile + ".")
+        elif fOutput != -1:
+            #if the operation was not canceled
+
+            #updated the progress message
+            self.listenerProgress("Finished", 100)
+
+            #parses the .srt subtitle file and export text to .txt file
+            SRTParser.extractTextFromSRT(str(outputFileSRT))
+
+            if self.objParamAutosub.boolOpenOutputFilesAuto:
+                #open both SRT and TXT output files
+                MyUtil.open_file(outputFileTXT)
+                MyUtil.open_file(outputFileSRT)
+
+    def __loopSelectedFiles(self):
+        self.signalLockGUI.emit()
+
+        langCode = self.objParamAutosub.langCode
+
+        #if output directory does not exist, creates it
+        pathOutputFolder = Path(self.objParamAutosub.outputFolder)
+
+        if not os.path.exists(pathOutputFolder):
+            os.mkdir(pathOutputFolder)
+        #if there the output file is not a directory
+        if not os.path.isdir(pathOutputFolder):
+            #force the user to select a different output directory
+            self.signalErrorMsg.emit("Error! Invalid output folder. Please choose another one.")
+        else:
+            #go ahead with autosub process
+            nFiles = len(self.objParamAutosub.listFiles)
+            for i in range(nFiles):
+                #does not continue the loop if user clicked cancel button
+                if not Ctr_Autosub.is_operation_canceled():
+                    self.__updateProgressFileYofN(i, nFiles)
+                    self.__runAutosubForMedia(i, langCode)
+
+            #if operation is canceled does not clear the file list
+            if Ctr_Autosub.is_operation_canceled():
+                self.signalResetGUIAfterCancel.emit()
+            else:
+                self.signalResetGUIAfterSuccess.emit()
+
+
+    def run(self):
+        Ctr_Autosub.init()
+        self.__loopSelectedFiles()
+        self.running = False
+
+    def cancel(self):
+       Ctr_Autosub.cancel_operation()

+ 0 - 0
autoSub_dev/pytranscriber/gui/__init__.py


BIN
autoSub_dev/pytranscriber/gui/__pycache__/__init__.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/gui/__pycache__/__init__.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/gui/__pycache__/__init__.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/gui/__pycache__/gui.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/gui/__pycache__/gui.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/gui/__pycache__/gui.cpython-39.pyc


+ 120 - 0
autoSub_dev/pytranscriber/gui/gui.py

@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'gui.ui'
+#
+# Created by: PyQt5 UI code generator 5.13.1
+#
+# WARNING! All changes made in this file will be lost!
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_window(object):
+    def setupUi(self, window):
+        window.setObjectName("window")
+        window.resize(1045, 487)
+        self.centralwidget = QtWidgets.QWidget(window)
+        self.centralwidget.setObjectName("centralwidget")
+        self.bSelectMedia = QtWidgets.QPushButton(self.centralwidget)
+        self.bSelectMedia.setGeometry(QtCore.QRect(10, 10, 141, 34))
+        self.bSelectMedia.setObjectName("bSelectMedia")
+        self.bConvert = QtWidgets.QPushButton(self.centralwidget)
+        self.bConvert.setEnabled(False)
+        self.bConvert.setGeometry(QtCore.QRect(200, 290, 341, 34))
+        self.bConvert.setObjectName("bConvert")
+        self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
+        self.progressBar.setGeometry(QtCore.QRect(20, 340, 1021, 23))
+        self.progressBar.setProperty("value", 0)
+        self.progressBar.setObjectName("progressBar")
+        self.labelCurrentOperation = QtWidgets.QLabel(self.centralwidget)
+        self.labelCurrentOperation.setGeometry(QtCore.QRect(170, 350, 871, 41))
+        self.labelCurrentOperation.setText("")
+        self.labelCurrentOperation.setObjectName("labelCurrentOperation")
+        self.bOpenOutputFolder = QtWidgets.QPushButton(self.centralwidget)
+        self.bOpenOutputFolder.setGeometry(QtCore.QRect(550, 290, 241, 34))
+        self.bOpenOutputFolder.setObjectName("bOpenOutputFolder")
+        self.bSelectOutputFolder = QtWidgets.QPushButton(self.centralwidget)
+        self.bSelectOutputFolder.setGeometry(QtCore.QRect(10, 180, 141, 34))
+        self.bSelectOutputFolder.setObjectName("bSelectOutputFolder")
+        self.qleOutputFolder = QtWidgets.QLineEdit(self.centralwidget)
+        self.qleOutputFolder.setGeometry(QtCore.QRect(160, 180, 861, 32))
+        self.qleOutputFolder.setText("")
+        self.qleOutputFolder.setReadOnly(True)
+        self.qleOutputFolder.setObjectName("qleOutputFolder")
+        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
+        self.groupBox.setGeometry(QtCore.QRect(160, 10, 871, 161))
+        self.groupBox.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
+        self.groupBox.setFlat(False)
+        self.groupBox.setCheckable(False)
+        self.groupBox.setObjectName("groupBox")
+        self.qlwListFilesSelected = QtWidgets.QListWidget(self.groupBox)
+        self.qlwListFilesSelected.setGeometry(QtCore.QRect(10, 30, 851, 121))
+        self.qlwListFilesSelected.setObjectName("qlwListFilesSelected")
+        self.bRemoveFile = QtWidgets.QPushButton(self.centralwidget)
+        self.bRemoveFile.setGeometry(QtCore.QRect(10, 50, 141, 34))
+        self.bRemoveFile.setObjectName("bRemoveFile")
+        self.labelProgressFileIndex = QtWidgets.QLabel(self.centralwidget)
+        self.labelProgressFileIndex.setGeometry(QtCore.QRect(30, 350, 131, 41))
+        self.labelProgressFileIndex.setText("")
+        self.labelProgressFileIndex.setObjectName("labelProgressFileIndex")
+        self.bCancel = QtWidgets.QPushButton(self.centralwidget)
+        self.bCancel.setGeometry(QtCore.QRect(470, 390, 108, 36))
+        self.bCancel.setObjectName("bCancel")
+        self.chbxOpenOutputFilesAuto = QtWidgets.QCheckBox(self.centralwidget)
+        self.chbxOpenOutputFilesAuto.setGeometry(QtCore.QRect(10, 220, 291, 32))
+        self.chbxOpenOutputFilesAuto.setChecked(True)
+        self.chbxOpenOutputFilesAuto.setObjectName("chbxOpenOutputFilesAuto")
+        self.horizontalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
+        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(200, 250, 591, 34))
+        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
+        self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
+        self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0)
+        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
+        self.labelSelectLang = QtWidgets.QLabel(self.horizontalLayoutWidget)
+        self.labelSelectLang.setObjectName("labelSelectLang")
+        self.horizontalLayout_5.addWidget(self.labelSelectLang)
+        self.cbSelectLang = QtWidgets.QComboBox(self.horizontalLayoutWidget)
+        self.cbSelectLang.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
+        self.cbSelectLang.setObjectName("cbSelectLang")
+        self.horizontalLayout_5.addWidget(self.cbSelectLang)
+        window.setCentralWidget(self.centralwidget)
+        self.menubar = QtWidgets.QMenuBar(window)
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 1045, 34))
+        self.menubar.setObjectName("menubar")
+        self.menuAbout = QtWidgets.QMenu(self.menubar)
+        self.menuAbout.setObjectName("menuAbout")
+        window.setMenuBar(self.menubar)
+        self.statusbar = QtWidgets.QStatusBar(window)
+        self.statusbar.setObjectName("statusbar")
+        window.setStatusBar(self.statusbar)
+        self.actionLicense = QtWidgets.QAction(window)
+        self.actionLicense.setObjectName("actionLicense")
+        self.actionDonation = QtWidgets.QAction(window)
+        self.actionDonation.setObjectName("actionDonation")
+        self.actionAbout_pyTranscriber = QtWidgets.QAction(window)
+        self.actionAbout_pyTranscriber.setObjectName("actionAbout_pyTranscriber")
+        self.menuAbout.addAction(self.actionLicense)
+        self.menuAbout.addAction(self.actionDonation)
+        self.menuAbout.addAction(self.actionAbout_pyTranscriber)
+        self.menubar.addAction(self.menuAbout.menuAction())
+
+        self.retranslateUi(window)
+        QtCore.QMetaObject.connectSlotsByName(window)
+
+    def retranslateUi(self, window):
+        _translate = QtCore.QCoreApplication.translate
+        window.setWindowTitle(_translate("window", "pyTranscriber - v1.6 - 21/01/2020"))
+        self.bSelectMedia.setText(_translate("window", "Select file(s)"))
+        self.bConvert.setText(_translate("window", "Transcribe Audio / Generate Subtitles"))
+        self.bOpenOutputFolder.setText(_translate("window", "Open Output Folder"))
+        self.bSelectOutputFolder.setText(_translate("window", "Output Location"))
+        self.groupBox.setTitle(_translate("window", "&List of files to generate transcribe audio / generate subtitles"))
+        self.bRemoveFile.setText(_translate("window", "Remove file(s)"))
+        self.bCancel.setText(_translate("window", "Cancel"))
+        self.chbxOpenOutputFilesAuto.setText(_translate("window", "Open output files automatically"))
+        self.labelSelectLang.setText(_translate("window", "Audio Language:"))
+        self.menuAbout.setTitle(_translate("window", "Abo&ut"))
+        self.actionLicense.setText(_translate("window", "&License"))
+        self.actionDonation.setText(_translate("window", "&DONATIONS"))
+        self.actionAbout_pyTranscriber.setText(_translate("window", "&About pyTranscriber"))

+ 266 - 0
autoSub_dev/pytranscriber/gui/gui.ui

@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>window</class>
+ <widget class="QMainWindow" name="window">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1045</width>
+    <height>487</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>pyTranscriber - v1.5 - 07/12/2020</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <widget class="QPushButton" name="bSelectMedia">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>10</y>
+      <width>141</width>
+      <height>34</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Select file(s)</string>
+    </property>
+   </widget>
+   <widget class="QPushButton" name="bConvert">
+    <property name="enabled">
+     <bool>false</bool>
+    </property>
+    <property name="geometry">
+     <rect>
+      <x>200</x>
+      <y>290</y>
+      <width>341</width>
+      <height>34</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Transcribe Audio / Generate Subtitles</string>
+    </property>
+   </widget>
+   <widget class="QProgressBar" name="progressBar">
+    <property name="geometry">
+     <rect>
+      <x>20</x>
+      <y>340</y>
+      <width>1021</width>
+      <height>23</height>
+     </rect>
+    </property>
+    <property name="value">
+     <number>0</number>
+    </property>
+   </widget>
+   <widget class="QLabel" name="labelCurrentOperation">
+    <property name="geometry">
+     <rect>
+      <x>170</x>
+      <y>350</y>
+      <width>871</width>
+      <height>41</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string/>
+    </property>
+   </widget>
+   <widget class="QPushButton" name="bOpenOutputFolder">
+    <property name="geometry">
+     <rect>
+      <x>550</x>
+      <y>290</y>
+      <width>241</width>
+      <height>34</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Open Output Folder</string>
+    </property>
+   </widget>
+   <widget class="QPushButton" name="bSelectOutputFolder">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>180</y>
+      <width>141</width>
+      <height>34</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Output Location</string>
+    </property>
+   </widget>
+   <widget class="QLineEdit" name="qleOutputFolder">
+    <property name="geometry">
+     <rect>
+      <x>160</x>
+      <y>180</y>
+      <width>861</width>
+      <height>32</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string/>
+    </property>
+    <property name="readOnly">
+     <bool>true</bool>
+    </property>
+   </widget>
+   <widget class="QGroupBox" name="groupBox">
+    <property name="geometry">
+     <rect>
+      <x>160</x>
+      <y>10</y>
+      <width>871</width>
+      <height>161</height>
+     </rect>
+    </property>
+    <property name="title">
+     <string>&amp;List of files to generate transcribe audio / generate subtitles</string>
+    </property>
+    <property name="alignment">
+     <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+    </property>
+    <property name="flat">
+     <bool>false</bool>
+    </property>
+    <property name="checkable">
+     <bool>false</bool>
+    </property>
+    <widget class="QListWidget" name="qlwListFilesSelected">
+     <property name="geometry">
+      <rect>
+       <x>10</x>
+       <y>30</y>
+       <width>851</width>
+       <height>121</height>
+      </rect>
+     </property>
+    </widget>
+   </widget>
+   <widget class="QPushButton" name="bRemoveFile">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>50</y>
+      <width>141</width>
+      <height>34</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Remove file(s)</string>
+    </property>
+   </widget>
+   <widget class="QLabel" name="labelProgressFileIndex">
+    <property name="geometry">
+     <rect>
+      <x>30</x>
+      <y>350</y>
+      <width>131</width>
+      <height>41</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string/>
+    </property>
+   </widget>
+   <widget class="QPushButton" name="bCancel">
+    <property name="geometry">
+     <rect>
+      <x>470</x>
+      <y>390</y>
+      <width>108</width>
+      <height>36</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Cancel</string>
+    </property>
+   </widget>
+   <widget class="QCheckBox" name="chbxOpenOutputFilesAuto">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>220</y>
+      <width>291</width>
+      <height>32</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Open output files automatically</string>
+    </property>
+    <property name="checked">
+     <bool>true</bool>
+    </property>
+   </widget>
+   <widget class="QWidget" name="horizontalLayoutWidget">
+    <property name="geometry">
+     <rect>
+      <x>200</x>
+      <y>250</y>
+      <width>591</width>
+      <height>34</height>
+     </rect>
+    </property>
+    <layout class="QHBoxLayout" name="horizontalLayout_5">
+     <item>
+      <widget class="QLabel" name="labelSelectLang">
+       <property name="text">
+        <string>Audio Language:</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="cbSelectLang">
+       <property name="sizeAdjustPolicy">
+        <enum>QComboBox::AdjustToContents</enum>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </widget>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>1045</width>
+     <height>34</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuAbout">
+    <property name="title">
+     <string>Abo&amp;ut</string>
+    </property>
+    <addaction name="actionLicense"/>
+    <addaction name="actionDonate"/>
+    <addaction name="actionAbout_pyTranscriber"/>
+   </widget>
+   <addaction name="menuAbout"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <action name="actionLicense">
+   <property name="text">
+    <string>&amp;License</string>
+   </property>
+  </action>
+  <action name="actionDonate">
+   <property name="text">
+    <string>&amp;DONATIONS</string>
+   </property>
+  </action>
+  <action name="actionAbout_pyTranscriber">
+   <property name="text">
+    <string>&amp;About pyTranscriber</string>
+   </property>
+  </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 0 - 0
autoSub_dev/pytranscriber/model/__init__.py


BIN
autoSub_dev/pytranscriber/model/__pycache__/__init__.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/model/__pycache__/__init__.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/model/__pycache__/__init__.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/model/__pycache__/param_autosub.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/model/__pycache__/param_autosub.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/model/__pycache__/param_autosub.cpython-39.pyc


+ 22 - 0
autoSub_dev/pytranscriber/model/param_autosub.py

@@ -0,0 +1,22 @@
+'''
+   (C) 2019 Raryel C. Souza
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+'''
+
+class Param_Autosub():
+
+    def __init__(self, listFiles, outputFolder, langCode,
+                boolOpenOutputFilesAuto):
+        self.listFiles = listFiles
+        self.outputFolder = outputFolder
+        self.langCode = langCode
+        self.boolOpenOutputFilesAuto = boolOpenOutputFilesAuto

+ 0 - 0
autoSub_dev/pytranscriber/util/__init__.py


BIN
autoSub_dev/pytranscriber/util/__pycache__/__init__.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/__init__.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/__init__.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/srtparser.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/srtparser.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/srtparser.cpython-39.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/util.cpython-37.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/util.cpython-38.pyc


BIN
autoSub_dev/pytranscriber/util/__pycache__/util.cpython-39.pyc


+ 49 - 0
autoSub_dev/pytranscriber/util/srtparser.py

@@ -0,0 +1,49 @@
+'''
+   (C) 2019 Raryel C. Souza
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+'''
+
+import re, sys
+
+class SRTParser(object):
+    @staticmethod
+    def extractTextFromSRT(fileSRT):
+        file_name = fileSRT
+        file_encoding = 'utf-8'
+
+        #loop through the lines for parsing
+        with open(file_name, encoding=file_encoding, errors='replace') as f:
+            lines = f.readlines()
+            new_lines = SRTParser.clean_up(lines)
+            new_file_name = file_name[:-4] + '.txt'
+
+        #write parsed txt file
+        with open(new_file_name, 'w', encoding=file_encoding) as f:
+            for line in new_lines:
+                f.write(line)
+
+    @staticmethod
+    def clean_up(lines):
+        regexSubtitleIndexNumber = re.compile("[0-9]+")
+
+        new_lines = []
+        for line in lines[1:]:
+            #if line empty or
+            #if line contains --> or
+            #if line matches the subtitle index regex
+            #then skip line
+            if (not line or not line.strip()) or ("-->" in line) or regexSubtitleIndexNumber.match(line):
+                continue
+            else:
+                #append line
+                new_lines.append(line)
+        return new_lines

+ 44 - 0
autoSub_dev/pytranscriber/util/util.py

@@ -0,0 +1,44 @@
+'''
+   (C) 2019 Raryel C. Souza
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+'''
+
+import platform
+import os
+import subprocess
+import socket
+
+class MyUtil(object):
+    @staticmethod
+    def open_file(path):
+        if platform.system() == "Windows":
+            os.startfile(path)
+        elif platform.system() == "Darwin":
+            subprocess.Popen(["open", path])
+        else:
+            subprocess.Popen(["xdg-open", path])
+
+    @staticmethod
+    def is_internet_connected():
+        try:
+            # connect to the host -- tells us if the host is actually
+            # reachable
+            s = socket.create_connection(("www.google.com", 80), 2)
+            s.close()
+            return True
+        except OSError:
+            pass
+        return False
+
+    @staticmethod
+    def percentage(currentval, maxval):
+        return 100 * currentval / float(maxval)

+ 14 - 0
autoSub_dev/run.py

@@ -0,0 +1,14 @@
+from autosub import DEFAULT_CONCURRENCY
+from autosub import DEFAULT_SUBTITLE_FORMAT
+from pytranscriber.control.ctr_main import Ctr_Main
+from pytranscriber.control.ctr_autosub import Ctr_Autosub
+
+def listener_progress(string, percent):
+    True
+    
+Ctr_Autosub.init()
+Ctr_Autosub.generate_subtitles("src.mp4",'zh'
+,listener_progress
+,output="script.txt"
+,concurrency=DEFAULT_CONCURRENCY,subtitle_file_format=DEFAULT_SUBTITLE_FORMAT)
+    

+ 39 - 0
autoSub_dev/script.txt

@@ -0,0 +1,39 @@
+1
+00:00:04,608 --> 00:00:08,960
+美廉社今天宣布日本棒球明星大谷翔平
+
+2
+00:00:09,216 --> 00:00:12,288
+獲選年度最佳男性運動員獎
+
+3
+00:00:12,544 --> 00:00:16,128
+報導回顧大谷翔平這個球季場上
+
+4
+00:00:16,384 --> 00:00:20,992
+機場下帶來的效應稱他重新定義現代棒球
+
+5
+00:00:21,504 --> 00:00:27,648
+美廉社一九三一年起每年選出年男性及女性運動員各一
+
+6
+00:00:28,416 --> 00:00:34,304
+另言絕大多數是美國運動員但也有少數外國運動員獲獎
+
+7
+00:00:35,072 --> 00:00:41,216
+今年大谷翔平及訓言最佳女性運動員大阪直美都是日本籍
+
+8
+00:00:41,984 --> 00:00:48,128
+台灣田徑女將紀政1970年獲獎美聯社工不得主的報導指出
+
+9
+00:00:48,896 --> 00:00:55,040
+大谷翔平2021年球季的成就重新定義現代棒球電影城
+
+10
+00:00:55,296 --> 00:00:56,320
+全世界木瓜

BIN
autoSub_dev/src.mp4


+ 405 - 0
autosub/__init__-0.4.0.py

@@ -0,0 +1,405 @@
+"""
+Defines autosub's main functionality.
+"""
+
+#!/usr/bin/env python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import argparse
+import audioop
+import json
+import math
+import multiprocessing
+import os
+import subprocess
+import sys
+import tempfile
+import wave
+
+import requests
+from googleapiclient.discovery import build
+from progressbar import ProgressBar, Percentage, Bar, ETA
+
+from autosub.constants import (
+    LANGUAGE_CODES, GOOGLE_SPEECH_API_KEY, GOOGLE_SPEECH_API_URL,
+)
+from autosub.formatters import FORMATTERS
+
+DEFAULT_SUBTITLE_FORMAT = 'srt'
+DEFAULT_CONCURRENCY = 10
+DEFAULT_SRC_LANGUAGE = 'en'
+DEFAULT_DST_LANGUAGE = 'en'
+
+
+def percentile(arr, percent):
+    """
+    Calculate the given percentile of arr.
+    """
+    arr = sorted(arr)
+    index = (len(arr) - 1) * percent
+    floor = math.floor(index)
+    ceil = math.ceil(index)
+    if floor == ceil:
+        return arr[int(index)]
+    low_value = arr[int(floor)] * (ceil - index)
+    high_value = arr[int(ceil)] * (index - floor)
+    return low_value + high_value
+
+
+class FLACConverter(object): # pylint: disable=too-few-public-methods
+    """
+    Class for converting a region of an input audio or video file into a FLAC audio file
+    """
+    def __init__(self, source_path, include_before=0.25, include_after=0.25):
+        self.source_path = source_path
+        self.include_before = include_before
+        self.include_after = include_after
+
+    def __call__(self, region):
+        try:
+            start, end = region
+            start = max(0, start - self.include_before)
+            end += self.include_after
+            temp = tempfile.NamedTemporaryFile(suffix='.flac')
+            command = ["ffmpeg", "-ss", str(start), "-t", str(end - start),
+                       "-y", "-i", self.source_path,
+                       "-loglevel", "error", temp.name]
+            use_shell = True if os.name == "nt" else False
+            subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+            return temp.read()
+
+        except KeyboardInterrupt:
+            return None
+
+
+class SpeechRecognizer(object): # pylint: disable=too-few-public-methods
+    """
+    Class for performing speech-to-text for an input FLAC file.
+    """
+    def __init__(self, language="en", rate=44100, retries=3, api_key=GOOGLE_SPEECH_API_KEY):
+        self.language = language
+        self.rate = rate
+        self.api_key = api_key
+        self.retries = retries
+
+    def __call__(self, data):
+        try:
+            for _ in range(self.retries):
+                url = GOOGLE_SPEECH_API_URL.format(lang=self.language, key=self.api_key)
+                headers = {"Content-Type": "audio/x-flac; rate=%d" % self.rate}
+
+                try:
+                    resp = requests.post(url, data=data, headers=headers)
+                except requests.exceptions.ConnectionError:
+                    continue
+
+                for line in resp.content.decode('utf-8').split("\n"):
+                    try:
+                        line = json.loads(line)
+                        line = line['result'][0]['alternative'][0]['transcript']
+                        return line[:1].upper() + line[1:]
+                    except IndexError:
+                        # no result
+                        continue
+
+        except KeyboardInterrupt:
+            return None
+
+
+class Translator(object): # pylint: disable=too-few-public-methods
+    """
+    Class for translating a sentence from a one language to another.
+    """
+    def __init__(self, language, api_key, src, dst):
+        self.language = language
+        self.api_key = api_key
+        self.service = build('translate', 'v2',
+                             developerKey=self.api_key)
+        self.src = src
+        self.dst = dst
+
+    def __call__(self, sentence):
+        try:
+            if not sentence:
+                return None
+
+            result = self.service.translations().list( # pylint: disable=no-member
+                source=self.src,
+                target=self.dst,
+                q=[sentence]
+            ).execute()
+
+            if 'translations' in result and result['translations'] and \
+                'translatedText' in result['translations'][0]:
+                return result['translations'][0]['translatedText']
+
+            return None
+
+        except KeyboardInterrupt:
+            return None
+
+
+def which(program):
+    """
+    Return the path for a given executable.
+    """
+    def is_exe(file_path):
+        """
+        Checks whether a file is executable.
+        """
+        return os.path.isfile(file_path) and os.access(file_path, os.X_OK)
+
+    fpath, _ = os.path.split(program)
+    if fpath:
+        if is_exe(program):
+            return program
+    else:
+        for path in os.environ["PATH"].split(os.pathsep):
+            path = path.strip('"')
+            exe_file = os.path.join(path, program)
+            if is_exe(exe_file):
+                return exe_file
+    return None
+
+
+def extract_audio(filename, channels=1, rate=16000):
+    """
+    Extract audio from an input file to a temporary WAV file.
+    """
+    temp = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
+    if not os.path.isfile(filename):
+        print("The given file does not exist: {}".format(filename))
+        raise Exception("Invalid filepath: {}".format(filename))
+    if not which("ffmpeg"):
+        print("ffmpeg: Executable not found on machine.")
+        raise Exception("Dependency not found: ffmpeg")
+    command = ["ffmpeg", "-y", "-i", filename,
+               "-ac", str(channels), "-ar", str(rate),
+               "-loglevel", "error", temp.name]
+    use_shell = True if os.name == "nt" else False
+    subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+    return temp.name, rate
+
+
+def find_speech_regions(filename, frame_width=4096, min_region_size=0.5, max_region_size=6): # pylint: disable=too-many-locals
+    """
+    Perform voice activity detection on a given audio file.
+    """
+    reader = wave.open(filename)
+    sample_width = reader.getsampwidth()
+    rate = reader.getframerate()
+    n_channels = reader.getnchannels()
+    chunk_duration = float(frame_width) / rate
+
+    n_chunks = int(math.ceil(reader.getnframes()*1.0 / frame_width))
+    energies = []
+
+    for _ in range(n_chunks):
+        chunk = reader.readframes(frame_width)
+        energies.append(audioop.rms(chunk, sample_width * n_channels))
+
+    threshold = percentile(energies, 0.2)
+
+    elapsed_time = 0
+
+    regions = []
+    region_start = None
+
+    for energy in energies:
+        is_silence = energy <= threshold
+        max_exceeded = region_start and elapsed_time - region_start >= max_region_size
+
+        if (max_exceeded or is_silence) and region_start:
+            if elapsed_time - region_start >= min_region_size:
+                regions.append((region_start, elapsed_time))
+                region_start = None
+
+        elif (not region_start) and (not is_silence):
+            region_start = elapsed_time
+        elapsed_time += chunk_duration
+    return regions
+
+
+def generate_subtitles( # pylint: disable=too-many-locals,too-many-arguments
+        source_path,
+        output=None,
+        concurrency=DEFAULT_CONCURRENCY,
+        src_language=DEFAULT_SRC_LANGUAGE,
+        dst_language=DEFAULT_DST_LANGUAGE,
+        subtitle_file_format=DEFAULT_SUBTITLE_FORMAT,
+        api_key=None,
+    ):
+    """
+    Given an input audio/video file, generate subtitles in the specified language and format.
+    """
+    audio_filename, audio_rate = extract_audio(source_path)
+
+    regions = find_speech_regions(audio_filename)
+
+    pool = multiprocessing.Pool(concurrency)
+    converter = FLACConverter(source_path=audio_filename)
+    recognizer = SpeechRecognizer(language=src_language, rate=audio_rate,
+                                  api_key=GOOGLE_SPEECH_API_KEY)
+
+    transcripts = []
+    if regions:
+        try:
+            widgets = ["Converting speech regions to FLAC files: ", Percentage(), ' ', Bar(), ' ',
+                       ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+            extracted_regions = []
+            for i, extracted_region in enumerate(pool.imap(converter, regions)):
+                extracted_regions.append(extracted_region)
+                pbar.update(i)
+            pbar.finish()
+
+            widgets = ["Performing speech recognition: ", Percentage(), ' ', Bar(), ' ', ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+
+            for i, transcript in enumerate(pool.imap(recognizer, extracted_regions)):
+                transcripts.append(transcript)
+                pbar.update(i)
+            pbar.finish()
+
+            if src_language.split("-")[0] != dst_language.split("-")[0]:
+                if api_key:
+                    google_translate_api_key = api_key
+                    translator = Translator(dst_language, google_translate_api_key,
+                                            dst=dst_language,
+                                            src=src_language)
+                    prompt = "Translating from {0} to {1}: ".format(src_language, dst_language)
+                    widgets = [prompt, Percentage(), ' ', Bar(), ' ', ETA()]
+                    pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+                    translated_transcripts = []
+                    for i, transcript in enumerate(pool.imap(translator, transcripts)):
+                        translated_transcripts.append(transcript)
+                        pbar.update(i)
+                    pbar.finish()
+                    transcripts = translated_transcripts
+                else:
+                    print(
+                        "Error: Subtitle translation requires specified Google Translate API key. "
+                        "See --help for further information."
+                    )
+                    return 1
+
+        except KeyboardInterrupt:
+            pbar.finish()
+            pool.terminate()
+            pool.join()
+            print("Cancelling transcription")
+            raise
+
+    timed_subtitles = [(r, t) for r, t in zip(regions, transcripts) if t]
+    formatter = FORMATTERS.get(subtitle_file_format)
+    formatted_subtitles = formatter(timed_subtitles)
+
+    dest = output
+
+    if not dest:
+        base = os.path.splitext(source_path)[0]
+        dest = "{base}.{format}".format(base=base, format=subtitle_file_format)
+
+    with open(dest, 'wb') as output_file:
+        output_file.write(formatted_subtitles.encode("utf-8"))
+
+    os.remove(audio_filename)
+
+    return dest
+
+
+def validate(args):
+    """
+    Check that the CLI arguments passed to autosub are valid.
+    """
+    if args.format not in FORMATTERS:
+        print(
+            "Subtitle format not supported. "
+            "Run with --list-formats to see all supported formats."
+        )
+        return False
+
+    if args.src_language not in LANGUAGE_CODES.keys():
+        print(
+            "Source language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if args.dst_language not in LANGUAGE_CODES.keys():
+        print(
+            "Destination language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if not args.source_path:
+        print("Error: You need to specify a source path.")
+        return False
+
+    return True
+
+
+def main():
+    """
+    Run autosub as a command-line program.
+    """
+    parser = argparse.ArgumentParser()
+    parser.add_argument('source_path', help="Path to the video or audio file to subtitle",
+                        nargs='?')
+    parser.add_argument('-C', '--concurrency', help="Number of concurrent API requests to make",
+                        type=int, default=DEFAULT_CONCURRENCY)
+    parser.add_argument('-o', '--output',
+                        help="Output path for subtitles (by default, subtitles are saved in \
+                        the same directory and name as the source path)")
+    parser.add_argument('-F', '--format', help="Destination subtitle format",
+                        default=DEFAULT_SUBTITLE_FORMAT)
+    parser.add_argument('-S', '--src-language', help="Language spoken in source file",
+                        default=DEFAULT_SRC_LANGUAGE)
+    parser.add_argument('-D', '--dst-language', help="Desired language for the subtitles",
+                        default=DEFAULT_DST_LANGUAGE)
+    parser.add_argument('-K', '--api-key',
+                        help="The Google Translate API key to be used. \
+                        (Required for subtitle translation)")
+    parser.add_argument('--list-formats', help="List all available subtitle formats",
+                        action='store_true')
+    parser.add_argument('--list-languages', help="List all available source/destination languages",
+                        action='store_true')
+
+    args = parser.parse_args()
+
+    if args.list_formats:
+        print("List of formats:")
+        for subtitle_format in FORMATTERS:
+            print("{format}".format(format=subtitle_format))
+        return 0
+
+    if args.list_languages:
+        print("List of all languages:")
+        for code, language in sorted(LANGUAGE_CODES.items()):
+            print("{code}\t{language}".format(code=code, language=language))
+        return 0
+
+    if not validate(args):
+        return 1
+
+    try:
+        subtitle_file_path = generate_subtitles(
+            source_path=args.source_path,
+            concurrency=args.concurrency,
+            src_language=args.src_language,
+            dst_language=args.dst_language,
+            api_key=args.api_key,
+            subtitle_file_format=args.format,
+            output=args.output,
+        )
+        print("Subtitles file created at {}".format(subtitle_file_path))
+    except KeyboardInterrupt:
+        return 1
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())

+ 434 - 0
autosub/__init__.py

@@ -0,0 +1,434 @@
+"""
+Defines autosub's main functionality.
+"""
+
+#!/usr/bin/env python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import argparse
+import audioop
+import math
+import multiprocessing
+import os
+from json import JSONDecodeError
+import subprocess
+import sys
+import tempfile
+import wave
+
+import json
+import requests
+try:
+    from json.decoder import JSONDecodeError
+except ImportError:
+    JSONDecodeError = ValueError
+
+from googleapiclient.discovery import build
+from progressbar import ProgressBar, Percentage, Bar, ETA
+
+from autosub.constants import (
+    LANGUAGE_CODES, GOOGLE_SPEECH_API_KEY, GOOGLE_SPEECH_API_URL,
+)
+from autosub.formatters import FORMATTERS
+
+DEFAULT_SUBTITLE_FORMAT = 'srt'
+DEFAULT_CONCURRENCY = 10
+DEFAULT_SRC_LANGUAGE = 'en'
+DEFAULT_DST_LANGUAGE = 'en'
+
+
+def percentile(arr, percent):
+    """
+    Calculate the given percentile of arr.
+    """
+    arr = sorted(arr)
+    index = (len(arr) - 1) * percent
+    floor = math.floor(index)
+    ceil = math.ceil(index)
+    if floor == ceil:
+        return arr[int(index)]
+    low_value = arr[int(floor)] * (ceil - index)
+    high_value = arr[int(ceil)] * (index - floor)
+    return low_value + high_value
+
+
+class FLACConverter(object): # pylint: disable=too-few-public-methods
+    """
+    Class for converting a region of an input audio or video file into a FLAC audio file
+    """
+    def __init__(self, source_path, include_before=0.25, include_after=0.25):
+        self.source_path = source_path
+        self.include_before = include_before
+        self.include_after = include_after
+
+    def __call__(self, region):
+        try:
+            start, end = region
+            start = max(0, start - self.include_before)
+            end += self.include_after
+            #delete=False necessary for running on Windows
+            temp = tempfile.NamedTemporaryFile(suffix='.flac', delete=False)
+            program_ffmpeg = which("ffmpeg")
+            command = [str(program_ffmpeg), "-ss", str(start), "-t", str(end - start),
+                       "-y", "-i", self.source_path,
+                       "-loglevel", "error", temp.name]
+            use_shell = True if os.name == "nt" else False
+            subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+            read_data = temp.read()
+            temp.close()
+            os.unlink(temp.name)
+            return read_data
+
+        except KeyboardInterrupt:
+            return None
+
+
+class SpeechRecognizer(object): # pylint: disable=too-few-public-methods
+    """
+    Class for performing speech-to-text for an input FLAC file.
+    """
+    def __init__(self, language="en", rate=44100, retries=3, api_key=GOOGLE_SPEECH_API_KEY):
+        self.language = language
+        self.rate = rate
+        self.api_key = api_key
+        self.retries = retries
+
+    def __call__(self, data):
+        try:
+            for _ in range(self.retries):
+                url = GOOGLE_SPEECH_API_URL.format(lang=self.language, key=self.api_key)
+                headers = {"Content-Type": "audio/x-flac; rate=%d" % self.rate}
+
+                try:
+                    resp = requests.post(url, data=data, headers=headers)
+                except requests.exceptions.ConnectionError:
+                    continue
+
+                for line in resp.content.decode('utf-8').split("\n"):
+                    try:
+                        line = json.loads(line)
+                        line = line['result'][0]['alternative'][0]['transcript']
+                        return line[:1].upper() + line[1:]
+                    except IndexError:
+                        # no result
+                        continue
+                    except JSONDecodeError:
+                        continue
+
+        except KeyboardInterrupt:
+            return None
+
+
+class Translator(object): # pylint: disable=too-few-public-methods
+    """
+    Class for translating a sentence from a one language to another.
+    """
+    def __init__(self, language, api_key, src, dst):
+        self.language = language
+        self.api_key = api_key
+        self.service = build('translate', 'v2',
+                             developerKey=self.api_key)
+        self.src = src
+        self.dst = dst
+
+    def __call__(self, sentence):
+        try:
+            if not sentence:
+                return None
+
+            result = self.service.translations().list( # pylint: disable=no-member
+                source=self.src,
+                target=self.dst,
+                q=[sentence]
+            ).execute()
+
+            if 'translations' in result and result['translations'] and \
+                'translatedText' in result['translations'][0]:
+                return result['translations'][0]['translatedText']
+
+            return None
+
+        except KeyboardInterrupt:
+            return None
+
+
+def which(program):
+    """
+    Return the path for a given executable.
+    """
+    def is_exe(file_path):
+        """
+        Checks whether a file is executable.
+        """
+        return os.path.isfile(file_path) and os.access(file_path, os.X_OK)
+    #necessary to run on Windows
+    if os.name == "nt":
+        program += ".exe"
+    fpath, _ = os.path.split(program)
+    if fpath:
+        if is_exe(program):
+            return program
+    else:
+        #looks for file in the script execution folder before checking on system path
+        current_dir = os.getcwd()
+        local_program = os.path.join(current_dir, program)
+        if is_exe(local_program):
+            return local_program
+        else:
+            for path in os.environ["PATH"].split(os.pathsep):
+                path = path.strip('"')
+                exe_file = os.path.join(path, program)
+                if is_exe(exe_file):
+                    return exe_file
+    return None
+
+
+def extract_audio(filename, channels=1, rate=16000):
+    """
+    Extract audio from an input file to a temporary WAV file.
+    """
+    temp = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
+    if not os.path.isfile(filename):
+        print("The given file does not exist: {}".format(filename))
+        raise Exception("Invalid filepath: {}".format(filename))
+    program_ffmpeg = which("ffmpeg")
+    if not program_ffmpeg:
+        print("ffmpeg: Executable not found on machine.")
+        raise Exception("Dependency not found: ffmpeg")
+    command = [str(program_ffmpeg), "-y", "-i", filename,
+               "-ac", str(channels), "-ar", str(rate),
+               "-loglevel", "error", temp.name]
+    use_shell = True if os.name == "nt" else False
+    subprocess.check_output(command, stdin=open(os.devnull), shell=use_shell)
+    return temp.name, rate
+
+
+def find_speech_regions(filename, frame_width=4096, min_region_size=0.5, max_region_size=6): # pylint: disable=too-many-locals
+    """
+    Perform voice activity detection on a given audio file.
+    """
+    reader = wave.open(filename)
+    sample_width = reader.getsampwidth()
+    rate = reader.getframerate()
+    n_channels = reader.getnchannels()
+    chunk_duration = float(frame_width) / rate
+
+    n_chunks = int(math.ceil(reader.getnframes()*1.0 / frame_width))
+    energies = []
+
+    for _ in range(n_chunks):
+        chunk = reader.readframes(frame_width)
+        energies.append(audioop.rms(chunk, sample_width * n_channels))
+
+    threshold = percentile(energies, 0.2)
+
+    elapsed_time = 0
+
+    regions = []
+    region_start = None
+
+    for energy in energies:
+        is_silence = energy <= threshold
+        max_exceeded = region_start and elapsed_time - region_start >= max_region_size
+
+        if (max_exceeded or is_silence) and region_start:
+            if elapsed_time - region_start >= min_region_size:
+                regions.append((region_start, elapsed_time))
+                region_start = None
+
+        elif (not region_start) and (not is_silence):
+            region_start = elapsed_time
+        elapsed_time += chunk_duration
+    return regions
+
+
+def generate_subtitles( # pylint: disable=too-many-locals,too-many-arguments
+        source_path,
+        output=None,
+        concurrency=DEFAULT_CONCURRENCY,
+        src_language=DEFAULT_SRC_LANGUAGE,
+        dst_language=DEFAULT_DST_LANGUAGE,
+        subtitle_file_format=DEFAULT_SUBTITLE_FORMAT,
+        api_key=None,
+    ):
+    """
+    Given an input audio/video file, generate subtitles in the specified language and format.
+    """
+
+    if os.name != "nt" and "Darwin" in os.uname():
+        #the default unix fork method does not work on Mac OS
+        #need to use forkserver
+        if 'forkserver' != multiprocessing.get_start_method(allow_none=True):
+            multiprocessing.set_start_method('forkserver')
+
+    audio_filename, audio_rate = extract_audio(source_path)
+
+    regions = find_speech_regions(audio_filename)
+
+    pool = multiprocessing.Pool(concurrency)
+    converter = FLACConverter(source_path=audio_filename)
+    recognizer = SpeechRecognizer(language=src_language, rate=audio_rate,
+                                  api_key=GOOGLE_SPEECH_API_KEY)
+
+    transcripts = []
+    if regions:
+        try:
+            widgets = ["Converting speech regions to FLAC files: ", Percentage(), ' ', Bar(), ' ',
+                       ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+            extracted_regions = []
+            for i, extracted_region in enumerate(pool.imap(converter, regions)):
+                extracted_regions.append(extracted_region)
+                pbar.update(i)
+            pbar.finish()
+
+            widgets = ["Performing speech recognition: ", Percentage(), ' ', Bar(), ' ', ETA()]
+            pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+
+            for i, transcript in enumerate(pool.imap(recognizer, extracted_regions)):
+                transcripts.append(transcript)
+                pbar.update(i)
+            pbar.finish()
+
+            if src_language.split("-")[0] != dst_language.split("-")[0]:
+                if api_key:
+                    google_translate_api_key = api_key
+                    translator = Translator(dst_language, google_translate_api_key,
+                                            dst=dst_language,
+                                            src=src_language)
+                    prompt = "Translating from {0} to {1}: ".format(src_language, dst_language)
+                    widgets = [prompt, Percentage(), ' ', Bar(), ' ', ETA()]
+                    pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
+                    translated_transcripts = []
+                    for i, transcript in enumerate(pool.imap(translator, transcripts)):
+                        translated_transcripts.append(transcript)
+                        pbar.update(i)
+                    pbar.finish()
+                    transcripts = translated_transcripts
+                else:
+                    print(
+                        "Error: Subtitle translation requires specified Google Translate API key. "
+                        "See --help for further information."
+                    )
+                    return 1
+
+        except KeyboardInterrupt:
+            pbar.finish()
+            pool.terminate()
+            pool.join()
+            print("Cancelling transcription")
+            raise
+
+    timed_subtitles = [(r, t) for r, t in zip(regions, transcripts) if t]
+    formatter = FORMATTERS.get(subtitle_file_format)
+    formatted_subtitles = formatter(timed_subtitles)
+
+    dest = output
+
+    if not dest:
+        base = os.path.splitext(source_path)[0]
+        dest = "{base}.{format}".format(base=base, format=subtitle_file_format)
+
+    with open(dest, 'wb') as output_file:
+        output_file.write(formatted_subtitles.encode("utf-8"))
+
+    os.remove(audio_filename)
+
+    return dest
+
+
+def validate(args):
+    """
+    Check that the CLI arguments passed to autosub are valid.
+    """
+    if args.format not in FORMATTERS:
+        print(
+            "Subtitle format not supported. "
+            "Run with --list-formats to see all supported formats."
+        )
+        return False
+
+    if args.src_language not in LANGUAGE_CODES.keys():
+        print(
+            "Source language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if args.dst_language not in LANGUAGE_CODES.keys():
+        print(
+            "Destination language not supported. "
+            "Run with --list-languages to see all supported languages."
+        )
+        return False
+
+    if not args.source_path:
+        print("Error: You need to specify a source path.")
+        return False
+
+    return True
+
+
+def main():
+    """
+    Run autosub as a command-line program.
+    """
+    parser = argparse.ArgumentParser()
+    parser.add_argument('source_path', help="Path to the video or audio file to subtitle",
+                        nargs='?')
+    parser.add_argument('-C', '--concurrency', help="Number of concurrent API requests to make",
+                        type=int, default=DEFAULT_CONCURRENCY)
+    parser.add_argument('-o', '--output',
+                        help="Output path for subtitles (by default, subtitles are saved in \
+                        the same directory and name as the source path)")
+    parser.add_argument('-F', '--format', help="Destination subtitle format",
+                        default=DEFAULT_SUBTITLE_FORMAT)
+    parser.add_argument('-S', '--src-language', help="Language spoken in source file",
+                        default=DEFAULT_SRC_LANGUAGE)
+    parser.add_argument('-D', '--dst-language', help="Desired language for the subtitles",
+                        default=DEFAULT_DST_LANGUAGE)
+    parser.add_argument('-K', '--api-key',
+                        help="The Google Translate API key to be used. \
+                        (Required for subtitle translation)")
+    parser.add_argument('--list-formats', help="List all available subtitle formats",
+                        action='store_true')
+    parser.add_argument('--list-languages', help="List all available source/destination languages",
+                        action='store_true')
+
+    args = parser.parse_args()
+
+    if args.list_formats:
+        print("List of formats:")
+        for subtitle_format in FORMATTERS:
+            print("{format}".format(format=subtitle_format))
+        return 0
+
+    if args.list_languages:
+        print("List of all languages:")
+        for code, language in sorted(LANGUAGE_CODES.items()):
+            print("{code}\t{language}".format(code=code, language=language))
+        return 0
+
+    if not validate(args):
+        return 1
+
+    try:
+        subtitle_file_path = generate_subtitles(
+            source_path=args.source_path,
+            concurrency=args.concurrency,
+            src_language=args.src_language,
+            dst_language=args.dst_language,
+            api_key=args.api_key,
+            subtitle_file_format=args.format,
+            output=args.output,
+        )
+        print("Subtitles file created at {}".format(subtitle_file_path))
+    except KeyboardInterrupt:
+        return 1
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())

BIN
autosub/__pycache__/__init__.cpython-37.pyc


Неке датотеке нису приказане због велике количине промена